Un programa en php que tiene que hacer muchas operaciones con la base de datos (lo cual tarda un tiempo considerable ya que hace un merge de una base grande casi completa) me tiraba el error...
Fatal error: Maximum execution time of 30 seconds exceeded in xxxx
Para arreglar el problema desde PHP le defino mas time_limit al script usando la función
set_time_limit(600);
... que limita el tiempo máximo de ejecución del script... acá más info: http://php.net/manual/es/function.set-time-limit.php
lunes, 11 de noviembre de 2013
Cambiar timeout en php
Cómo setear variables globales en MySQL
Desde línea de comandos (consola linux)...
Listo!
:-P
#>mysql -uroot -e "show variables like '%timeout';" -p
+----------------------------+-------+ | Variable_name | Value | +----------------------------+-------+ | connect_timeout | 10 | | delayed_insert_timeout | 300 | | innodb_lock_wait_timeout | 50 | | innodb_rollback_on_timeout | OFF | | interactive_timeout | 28800 | | net_read_timeout | 30 | | net_write_timeout | 60 | | slave_net_timeout | 3600 | | table_lock_wait_timeout | 50 | | wait_timeout | 28800 | +----------------------------+-------+
10 rows in set (0.00 sec)
#>mysql -uroot -e "SET GLOBAL net_read_timeout=600;" -p
#>mysql -uroot -e "show variables like '%timeout';" -p
+----------------------------+-------+ | Variable_name | Value | +----------------------------+-------+ | connect_timeout | 10 | | delayed_insert_timeout | 300 | | innodb_lock_wait_timeout | 50 | | innodb_rollback_on_timeout | OFF | | interactive_timeout | 28800 | | net_read_timeout | 600 | | net_write_timeout | 60 | | slave_net_timeout | 3600 | | table_lock_wait_timeout | 50 | | wait_timeout | 28800 | +----------------------------+-------+10 rows in set (0.00 sec)
Listo!
:-P
viernes, 11 de octubre de 2013
miércoles, 9 de octubre de 2013
miércoles, 25 de septiembre de 2013
Borrar muchos registros en CouchDB
Bueno, acá les dejo un script en Perl para borrar todos los registros obtenidos de una vista de CouchDB.
use strict; use Store::CouchDB; # database my $couch_db = Store::CouchDB->new({ user => '<mi_user>', pass => '<mi_clave>' }); $couch_db->config({db => '<nombre_de_la_base>'}); my $mis_docs = $couch_db->get_view({ view => '<documento_de_diseño>/<nombre_de_la_vista>' });Espero que les sea útil.while ( my ($key, $value) = each($mis_docs) ) { print "borrando registro id: $key\n"; $couch_db->del_doc({id => $key}) or warn "err\n"; }
martes, 10 de septiembre de 2013
CouchDB - Manejo de usuarios
Bueno, acá como crear usuarios, darles permisos y roles, etc...
Primeros, para el administrador, ni bien entramos deberíamos ponerle clave al administrador, eso de hace desde el futon (por defecto en http://localhost:5984/_utils/) y haciendo click en la parte inferior derecha, donde dice " Welcome to Admin Party! Everyone is admin. Fix this" (en el Fix this :-). Y ahí nos pedirá Usuario y Clave.
Después deberíamos entrar en las bases de datos que tengamos y setearle miembros y administradores, ya que las bases que no tienen ningún miembro son públicas.
También si queremos deshabilitar el acceso anónimo a la base debemos entrar en Tools->Configuration (en la parte derecha del futon) y setear en true la variable require_valid_user.
Hay que tener en cuenta que para que no permita acceso a cualquier usuario hay que ingresar al menos un valor en estos campos, ya que si dejamos por ejemplo los Roles vacíos va a dejar entrar a cualquiera, porque la base no tiene ningún rol asignado (lo mismo para miembros); entonces cualquiera podrá modificar documentos, aunque los documentos de diseño solo podrán ser modificados por administradores del servidor.
En nuestro servidor de base de datos podemos crear diferentes roles para los usuario. Como vimos en la creación de usuarios, le podemos dar al mismo usuario uno o más roles. Bueno, ahora entrando en nuestra base y yendo a "Security" (en el menú superior de Futon) podemos darle a esos roles permisos de administrador o miembro de la base; lo que hace que todos los usuarios que tengan el rol adquieran sobre nuestra base los permisos que le demos al rol.
Primeros, para el administrador, ni bien entramos deberíamos ponerle clave al administrador, eso de hace desde el futon (por defecto en http://localhost:5984/_utils/) y haciendo click en la parte inferior derecha, donde dice " Welcome to Admin Party! Everyone is admin. Fix this" (en el Fix this :-). Y ahí nos pedirá Usuario y Clave.
Después deberíamos entrar en las bases de datos que tengamos y setearle miembros y administradores, ya que las bases que no tienen ningún miembro son públicas.
También si queremos deshabilitar el acceso anónimo a la base debemos entrar en Tools->Configuration (en la parte derecha del futon) y setear en true la variable require_valid_user.
Tipos de usuarios
En CouchDB se pueden setear tres tipos de usuario:- Adminsitradores: como vimos arriba, los usuarios admin del servidor tienen todos los privilegios.
- Administradores de la base de datos: tienen todos los privilegios dentro de la base de datos de la que son administrador, pero no pueden acceder a otras bases ni crear o borrar otras bases ni la propia.
- Y por último los miembros de la base de datos: pueden ver, crear y editar documentos en la base, excepto los de diseño.
Hay que tener en cuenta que para que no permita acceso a cualquier usuario hay que ingresar al menos un valor en estos campos, ya que si dejamos por ejemplo los Roles vacíos va a dejar entrar a cualquiera, porque la base no tiene ningún rol asignado (lo mismo para miembros); entonces cualquiera podrá modificar documentos, aunque los documentos de diseño solo podrán ser modificados por administradores del servidor.
Usuarios
Para crear usuarios en nuestra base es muy facil, se crean como documentos en la base _users (si quisiéramos usar otro nombre se setea en la propiedad authentication_db de configuración). Con lo cual para crear el usuario pepe haríamos:{ "_id": "org.couchdb.user:pepe", "name": "pepe", "password": "password_de_pepe", "roles": ["DataEntry" ], "type": "user" }Para los usuarios, el _id debe comenzar con "org.couchdb.user:nombre de usuario" y nombre de usuario debe coincidir con name. En "roles" ponemos los roles a los que el usuario pertenece.
Roles
En nuestro servidor de base de datos podemos crear diferentes roles para los usuario. Como vimos en la creación de usuarios, le podemos dar al mismo usuario uno o más roles. Bueno, ahora entrando en nuestra base y yendo a "Security" (en el menú superior de Futon) podemos darle a esos roles permisos de administrador o miembro de la base; lo que hace que todos los usuarios que tengan el rol adquieran sobre nuestra base los permisos que le demos al rol.
martes, 3 de septiembre de 2013
Vistas en CouchDB
Para utilizar los datos de nuestra base CouchDB se utilizan vistas (views), que se escriben en JavaScript, las hay de dos tipos:
- Las "vistas temporales" (temporary views) usadas mayormente en desarrollo ya que son muy lentas.
- Las "vitas permanentes" que son documentos "especiales" de la base que se almacenan con el prefijo "_design"
Funciones de mapeo (Map Functions)
Cómo crear la vista en JavaScript... para explicar un ejemplo. Supongamos que tenemos documentos correspondientes a{ "_id": "320c8f17caa2698efdc307d7e6000b73", "type": "persona", "nombre": "Juan", "apellido": "Perez", "documento": 45678913 }
A los documentos les ponemos un type (o tipo) para identificarlos nosotros, bueno, si queremos una vista para ver las "personas" tenemos:
{ "_id": "_design/personas", "_rev": "1-4530f2212bd4df41abeb18285a1ec450", "language": "javascript", "views": { "personas": { "map": "function(doc) {\n if (doc.type == 'persona'){\n emit(doc.documento, doc);\n }\n}" } } }
Analizando lo último, vemos que cree un documento con el id especial "_design/personas" (que lo identifica como documento de diseño), y que tiene una vista también llamada "personas" que tiene a su vez una función de mapeo.
Las funciones de mapeo se ejecutan para crear los índices de la base*1, se corren para todos los elementos de la misma. La función recibe doc, que es el documento de que se trate (se ejecuta una vez por cada documento), por eso lo primero que hacemos es ver si se trata de un documento de "persona", si es así corresponde emitir un resultado para le índice, que debe ser un par clave/valor, en este caso ponemos dni (doc.dni será la clave) y el documento mismo.*2
*1 La primera vez que usa una vista puede tardar en responder (dependiendo de la cantidad de datos que involucre) ya que es el momento en que se crea el índice mapeado (no cuando se graba la vista, sino la primera vez que se la invoca).
*2 Siempre debemos llamar a la función emit para envíe el par clave/valor para el índice.
Fuente: http://wiki.apache.org/couchdb/Introduction_to_CouchDB_views
viernes, 30 de agosto de 2013
CouchDB desde perl, primeros pasos
CouchDB es una base de datos NOSQL de apache. Según leemo en Wikipedia "Se trata de una base de datos NoSQL que emplea JSON para almacenar los datos, JavaScript como lenguaje de consulta por medio de MapReduce y HTTP como API.1 Una de sus características más peculiares es la facilidad con la que permite hacer replicaciones.". ¡FANTÁSTICO!
Bueno, veamos como hacer desde perl para conectar a esta base y hacer algunas operaciones (simple ABM)...
# Para empezar usamos estos modulitos perl que baje de cpan # Mas info dobre Store::CopuchDB en http://search.cpan.org/~norbu/Store-CouchDB-2.8/lib/Store/CouchDB.pm
use strict; use Store::CouchDB; use JSON; # database my $couch_db = Store::CouchDB->new();
# si tenemos la base con usuario y pass hacemos
# my $couch_db = Store::CouchDB->new( { user => '<mi user>', pass => 'mi pass', host => 'localhost o lo que sea' } );
#creo una base de datos llamada 'pancho' $couch_db->create_db('pancho'); print "base creada\n"; print "enter para seguir..."; <STDIN>; #le configuro que use la base pancho $couch_db->config({db => 'pancho'}); print "base seteada\n"; #Agrego un documento a mi base couchDB my $doc = decode_json (' { "type":"persona", "nombre":"Felipe", "apodo":"Pipe", "telefonos":[ {"tipo":"casa","numero":"123456789"} ] }'); $couch_db->put_doc({doc => $doc}); print "Pipe agregado\nenter para seguir..."; <STDIN>; $doc = decode_json (' { "type":"persona", "nombre":"Alberto", "apodo":"Beto", "telefonos":[ ] }'); my $inserted_doc = $couch_db->put_doc({doc => $doc}); print "Id del documento insertado (_id): $inserted_doc\n"; print "Beto agregado\nenter para seguir..."; <STDIN>; $doc = decode_json (' { "type":"persona", "nombre":"Francisco", "apodo":"Pancho", "telefonos":[ {"tipo":"casa","numero":"123456789"}, {"tipo":"trabajo","numero":"987654321"}, {"tipo":"celular","numero":"963258741" } ] }'); $couch_db->put_doc({doc => $doc}); print "Pancho agregado\nenter para seguir..."; <STDIN>; #leo un documento por su id my $mi_doc = $couch_db->get_doc({id => $inserted_doc}); print "\n\nJSON:" . encode_json($mi_doc) . "\n\n"; print "Apodo de documento traido: " . $mi_doc->{apodo} . "*******\n"; $mi_doc->{apodo} = 'kuki'; #cambio el apodo print "Apodo nuevo: " . $mi_doc->{apodo} . "\n"; #actualizo el documento $couch_db->put_doc({doc => $mi_doc}); #borro el documento $couch_db->del_doc({id => $inserted_doc}); #borro la base print "Registro modificado\nenter para seguir..."; <STDIN>; print "\n"; 1;
La instalación de CouchDB en windows es trivial, corre el instalador que se baja de http://couchdb.apache.org/ y listo.
yo para laburar perl desde windows uso DWIM Perl,l una genial distribución que tiene un perl basado en strawberry perl, muchos módulos de cpan preinstalados y el IDE Padre para programar en perl, que está muy copado.
Con estas herramientas instaladas para hacer el ejemplo de arriba solo debemos hacer
cpan -i JSON
cpan -i Store::CouchDB
Agregado 4/2014:
Luego de usar durante algún tiempo esta versión de Store::CouchDB de CPAN descubro que tengo un problema con los valores false y true, el problema viene de que perl no tiene false y true propiamente dichos (0 es false, etc) por lo que si quiero poner un valor false en CouchDB lo guarda como el string "false" (lo mismo con true).
Este problema se soluciona usando
Types::Serialiser::false
o
Types::Serialiser::true
También estoy usando una versión más reciente de Store::CouchDB, al momento la 3.6 que extrañamente no se encuentra en CPAN pero sí en github, podemos bajarla desde https://github.com/norbu09/Store-CouchDB.
jueves, 18 de julio de 2013
Usar funciones de PHP desde Perl fácil
A veces se hace necesario llamar a funciones de php desde un programa en perl. Eso es posible haciendo lo siguiente.
Creamos el archivo test.php con:
<?php function testPHP($value){ echo "Pruyeba111 de PHP:" . $value; } ?>
Luego creamos el archivo perl que usara la función de php y nos queda así:
#!/usr/bin/perl
my $res = `php -r '
include_once "test.php";
testPHP ("\n\nTEEST2\n\n");
' `;
print "\n\nResultado: $res";
Observar que la comilla en la línea de my $res= es una comilla simple que se usa en perl para ejecutar instrucciones de "afuera" del perl, es similar a escribir por consola o una llamada a la función "system(xxx)" de perl.
lunes, 15 de julio de 2013
Subir archivos al servidor GLPI con FusionInventory manualmente
Para agregar archivos (files) al servidor, cuando creamos un paquete (package), en .
Los archivos deben ser agregados en la carpeta
<server root>/files/_plugins/fusinvdeploy/upload
Todos los archivos que ponga en esa carpeta los verá en la creación del package de Fusion Inventory yendo por Plugins->Package Management y seleccionando o creando un paquete, cuando hace click en "Add file" en Files to copy on computer.
Los archivos deben ser agregados en la carpeta
<server root>/files/_plugins/fusinvdeploy/upload
Todos los archivos que ponga en esa carpeta los verá en la creación del package de Fusion Inventory yendo por Plugins->Package Management y seleccionando o creando un paquete, cuando hace click en "Add file" en Files to copy on computer.
lunes, 8 de julio de 2013
Imprimir en impresora de etiquetas SATO desde PowerShell
Aquí les dejo un pequeño programa que me habilita la impresión desde PowerShell en impresoras de etiquetas SATO. (parte del código salio de http://social.msdn.microsoft.com/Forums/en-US/94967169-a9ee-45db-9c8a-acd6f173680d/rawprinthelper-for-bold-font)...
El archivo PrinterHelper.ps1 es
Con lo que estaríamos imprimiendo una etiqueta con el valor 555 en code39, imprimiendo el número 555 debajo.
Esta misma clase se puede usar para imprimir desde .Net (con c#)
El archivo PrinterHelper.ps1 es
clear $src = @' using System; using System.IO; using System.Runtime.InteropServices; public class RawPrinterHelper { // Structure and API declarions: [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public class DOCINFOA { [MarshalAs(UnmanagedType.LPStr)] public string pDocName; [MarshalAs(UnmanagedType.LPStr)] public string pOutputFile; [MarshalAs(UnmanagedType.LPStr)] public string pDataType; } #region "Imports" [DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd); [DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] public static extern bool ClosePrinter(IntPtr hPrinter); [DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di); [DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] public static extern bool EndDocPrinter(IntPtr hPrinter); [DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] public static extern bool StartPagePrinter(IntPtr hPrinter); [DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] public static extern bool EndPagePrinter(IntPtr hPrinter); [DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten); #endregion public RawPrinterHelper(){} // SendBytesToPrinter() // When the function is given a printer name and an unmanaged array // of bytes, the function sends those bytes to the print queue. // Returns true on success, false on failure. public bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount) { Int32 dwError = 0, dwWritten = 0; IntPtr hPrinter = new IntPtr(0); DOCINFOA di = new DOCINFOA(); bool bSuccess = false; // Assume failure unless you specifically succeed. di.pDocName = "My document"; di.pDataType = "RAW"; try { // Open the printer. if (OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero)) { // Start a document. if (StartDocPrinter(hPrinter, 1, di)) { // Start a page. if (StartPagePrinter(hPrinter)) { // Write your bytes. bSuccess = WritePrinter(hPrinter, pBytes, dwCount, out dwWritten); EndPagePrinter(hPrinter); } EndDocPrinter(hPrinter); } ClosePrinter(hPrinter); } } catch (Exception ex) { throw (ex); } // If you did not succeed, GetLastError may give more information // about why not. if (bSuccess == false) { dwError = Marshal.GetLastWin32Error(); } return bSuccess; } public bool SendStringToPrinter(string szPrinterName, string szString) { IntPtr pBytes; Int32 dwCount; szString = reemplazarCaracteres(szString); // How many characters are in the string? dwCount = szString.Length; // Assume that the printer is expecting ANSI text, and then convert // the string to ANSI text. pBytes = Marshal.StringToCoTaskMemAnsi(szString); // Send the converted ANSI string to the printer. SendBytesToPrinter(szPrinterName, pBytes, dwCount); Marshal.FreeCoTaskMem(pBytes); return true; } private string reemplazarCaracteres(string PrintCommand) { PrintCommand = PrintCommand.Replace("<STX>", ((char)02).ToString()); PrintCommand = PrintCommand.Replace("<ETX>", ((char)03).ToString()); PrintCommand = PrintCommand.Replace("<ESC>", ((char)27).ToString()); return PrintCommand; } } '@ Add-Type -TypeDefinition $src -Language CSharpVersion3 $PrinterHelper = new-object RawPrinterHelperSu uso es simple, por ejemplo desde otro archivo ps1 hacemos
. .\PrinterHelper.ps1 $PrinterHelper.SendStringToPrinter('\\PROG03\sato cg408', '<STX><ESC>A1002400880<ESC>A<ESC>H0030<ESC>V0030<ESC>BT101030100<ESC>BW03100*555*<ESC>H0030<ESC>V0133<ESC>WB0555<ESC>Q1<ESC>Z<ETX>')
Con lo que estaríamos imprimiendo una etiqueta con el valor 555 en code39, imprimiendo el número 555 debajo.
Esta misma clase se puede usar para imprimir desde .Net (con c#)
Etiquetas:
.NET,
C#,
imprimir,
PowerShell,
programación,
SATO,
SBPL,
script,
shell
Imprimir etiquetas con impresora SATO GC408TT
La impresión en este modelo de impresora se hace utilizando el lenguaje SBPL. En caso de este modelo de impresora tiene una definición de 8 puntos por milímetro y las medidas se indican en puntos, por lo cual deberemos multiplicar por 8 para tener el tamaño de un mm.
Las impresiones empiezan con <STX> y terminan con <ETX>.
<ESC>A1: para establecer el tamaño de la etiqueta (vendría a ser como el tamaño del papel), el formato es <ESC>A1aaaaabbbb // a = Label Length b = Label Width
Luego en <ESC>H0025<ESC>V0425 indica el desplazamiento en x e y (horizontal y vertical) respectivamente de lo que se va a imprimir.
<ESC>BT101030103 indica el tipo de código
BTabbccddee Bar Codes. Variable Ratio. provides the ability to print a bar code with a
ratio other than those specified through the standard bar code commands
(B, BD, and D).
a = Bar code option:
0: Codabar
1: Code 39
2: Interleaved 2 of 5
5: Industrial 2 of 5
6: Matrix 2 of 5
bb = Narrow space in dots (01-99)
cc = Wide space in dots (01-99)
dd = Narrow bar in dots (01-99)
ee = Wide bar in dots (01-99)
luego de eso sigue:
<ESC>BWaabbb
aa = Expansion factor by which the2width of all bars and spaces will be
increased (01 to 12)
bbb = Bar height by dot (004 to 999 dots)
Place immediately following the <ESC>BT command and preceding data to be
encoded.
EXAMPLE <ESC>A
<ESC>H0050<ESC>V0050<ESC>BT101030103
<ESC>BW04100*1234*
<ESC>Q1
<ESC>Z
Ejemplo:
<STX>
<ESC>A1002400880
<ESC>A
<ESC>H0030<ESC>V0030<ESC>BT101030100<ESC>BW03100*4445*
<ESC>H0030<ESC>V0133<ESC>WB04445
<ESC>Q1
<ESC>Z
<ETX>
lunes, 24 de junio de 2013
Instalando Symfony
Lo bajo de http://symfony.com/download (el archivo actual es Symfony_Standard_Vendors_2.3.1.tgz) y lo dejo en /var/www/. Luego le hago
tar xzvf Symfony_Standard_Vendors_2.3.1.tgz
con ésto se me descomprimió y queda en la carpeta /var/www/Symfony a la cual entro con
cd Symfony
y una vez ahí corremos
php app/check.php
que nos va a verificar que nuestro sistema tenga los requisitos necesarios para que funcione bien la aplicación. En mi caso me tiro algunos errores en el archivo php.ini que tuve que resolver. Observar que en la primer parte de la respuesta que nos da check.php está indicado cuál archivo php.ini está usando Symfony (en nuestro sistema puede haber más de un php.ini).
Casi todos los errores fueron de fácil resolución, pero tuve uno warning "WARNING short_open_tag should be disabled in php.ini Set short_open_tag to off in php.ini*." que me costó un poco más y fue porque no me tomaba el valor del short_open_tag = Off aunque yo lo puse y esto era porque el "short_open_tag" estaba dos veces en el php.ini, con lo cual, el problema se soluciona, comentando una de las líneas sobrantes.
tar xzvf Symfony_Standard_Vendors_2.3.1.tgz
con ésto se me descomprimió y queda en la carpeta /var/www/Symfony a la cual entro con
cd Symfony
y una vez ahí corremos
php app/check.php
que nos va a verificar que nuestro sistema tenga los requisitos necesarios para que funcione bien la aplicación. En mi caso me tiro algunos errores en el archivo php.ini que tuve que resolver. Observar que en la primer parte de la respuesta que nos da check.php está indicado cuál archivo php.ini está usando Symfony (en nuestro sistema puede haber más de un php.ini).
Casi todos los errores fueron de fácil resolución, pero tuve uno warning "WARNING short_open_tag should be disabled in php.ini Set short_open_tag to off in php.ini*." que me costó un poco más y fue porque no me tomaba el valor del short_open_tag = Off aunque yo lo puse y esto era porque el "short_open_tag" estaba dos veces en el php.ini, con lo cual, el problema se soluciona, comentando una de las líneas sobrantes.
jueves, 23 de mayo de 2013
Powershell y passwords
EnPower Shell a veces tenemos la necesidad de manejar claves, para lo que tenemos que por ejemplo para leer una clave y que aparezcan los típicos asteriscos, cada vez que pulsamos una tecla hacemos:
Donde, con "-AsSecureString" le indicamos que guarde lo ingresado en un string seguro. Bueno, ahora si ponemos
vemos que la respuesta es
Lo cual nos deja un poco perplejos, para ver el valor ingresado debemos hacer
...lo que nos mostrará la clave ingresada por el usuario.
$psw = Read-Host "Ingrese la clave" -AsSecureString
Donde, con "-AsSecureString" le indicamos que guarde lo ingresado en un string seguro. Bueno, ahora si ponemos
Write-Host $psw
vemos que la respuesta es
System.Security.SecureString
Lo cual nos deja un poco perplejos, para ver el valor ingresado debemos hacer
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($psw) Write-Host [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
...lo que nos mostrará la clave ingresada por el usuario.
Etiquetas:
Power Shell,
PowerShell,
programación,
script
miércoles, 15 de mayo de 2013
PowerShell: Búsqueda Binaria en arrays de objetos personalizados
El problema del IComparer
Siguiendo con el tema de la búsqueda rápida (haciendo búsqueda binaria), en éste artículo ya había encontrado cómo hacer una búsqueda binaria sobre un ArrayList desde Power Shell, pero al complicar un poco el tema, usando arreglos de objetos propios encontré un problema...El problema es que al ser objetos propios debemos indicarle sobre qué campo hacer la búsqueda y cómo se ordenan los objetos... El mismo problema tenemos al ordenar (hacer un sort) sobre un Array o ArrayList.
Veamos a un ejemplo, tenemos un ArrayList de objetos Empleado, con atributos Nombre, Apellido, Legajo... por ej uso esta funcion para crearlos:
function Nuevo-Empleado(){ param ($Nombre, $Apellido, $Codigo) $empleado= New-Object PSObject $empleado| Add-Member -type NoteProperty -Name Nombre -Value $Nombre $empleado| Add-Member -type NoteProperty -Name Apellido -Value $Apellido $empleado| Add-Member -type NoteProperty -Name Legajo -Value $Codigo return $empleado }
Y supongamos que los cargamos de un archivo csv desordenado y queremos buscar por nro de legajo...
[System.Collections.ArrayList] $listaEmpleados = New-Object System.Collections.ArrayList $listaEmpleados = Import-Csv-h Nombre, Apellido, Codigo
$ listaEmpleados = $ listaEmpleados | sort Codigo# ordeno por codigo
Ahora el tema es.. cómo hace para ordenar por código... bueno, supongamos que código es string... luego, para poder hacer el BinarySearch...
La función de comparación
$src = @' using System; using System.Collections; using System.Management.Automation; public sealed class ScriptBlockComparer : IComparer { ScriptBlock _Comparer; public ScriptBlockComparer(ScriptBlock Comparer) { ComparerScript = Comparer; } public ScriptBlock ComparerScript { get { return _Comparer; } set { _Comparer = value; } } public int Compare(object x, object y) { try { return (int)ComparerScript.Invoke(x, y)[0].BaseObject; } catch(Exception ex) { throw new InvalidOperationException("Comparer Script failed to return an integer!", ex); } } } '@ Add-Type -TypeDefinition $src -Language CSharpVersion3 $cmp = New-Object ScriptBlockComparer { Param($primero, $segundo) $pos = $primero.Codigo.CompareTo($segundo) return $pos } ....... .......... mas codigo ........... ... y... $pos = $list.BinarySearch($codigoABuscar, $cmp)
Y nos devuelve en pos la posición del elemento buscado en el array (empezando desde 0) y un nro <0 si no se encontró. Espero les sirva de ayuda!
Nota: si les tira error con la version de .Net pueden intentar cambiar
Add-Type -TypeDefinition $src -Language CSharpVersion3
Por:
Add-Type -TypeDefinition $src -Language CSharp
Ya que espera tener instalado el Framework .Net versión 3.5
Etiquetas:
binaria,
búsqueda,
IComparer,
Power Shell,
PowerShell,
programación
martes, 7 de mayo de 2013
bat2sh
Cómo convertir fácilmente un archivo bat de windows en un sh para linux.
Para eso comencé a crear este pequeño script en perl (mejorable por cierto) para automatizar un poco esta tarea. Dejo el código en su estado actual aquí abajo, pueden encontrar la última versión (y participar en ella para mejorarla) en éste github.#!/usr/bin/perl sub cat_ { local *F; open F, $_[0] or return; my @l =; wantarray() ? @l : join '', @l } sub output { my $f = shift; local *F; open F, ">$f" or die "output in file $f failed: $!\n"; print F foreach @_; 1 } if (@ARGV != 2) { die "Usage: bat2sh.pl <input .bat file> <output .sh file>\n"; } my @contents = cat_($ARGV[0]); foreach my $line (@contents) { # rem -> # $line =~ s/rem /# /i; # move -> mv $line =~ s/^\s*move\b/mv/; # del -> rm $line =~ s/^\s*del\b/rm/; # dos eol to unix eol $line =~ s/\r\n/\n/; # set $line =~ s/^\s*set //i; # \ -> / $line =~ s/\\/\//g; # copy -> cp if ($line =~ m/^\s*copy\b/ig){ $line =~ s/^\s*copy\b/cp/ig; $line =~ s/\n//; #remove eol $line .= " ./\n"; } # %varName% -> $varName while ($line =~ m/(%\w*%)/ig){ my $word = "\$" . substr($1, 1, -1); $line =~ s/(%\w*%)/$word/ig; } # if ERRORLEVEL 1 goto ERROR -> if [ "$?" = "1" ]; then sub_error fi if ($line =~ m/^\s*if\s*ERRORLEVEL\s*1\s*goto\s*(\w*)\s*$/ig){ $line = "if [ \"\$?\" = \"1\" ]; then \n exit 1\nfi\n"; } } my $line = "#!/bin/sh\n\n\n"; unshift @contents, $line; output $ARGV[1], @contents;
lunes, 6 de mayo de 2013
Sonidos desde power shell
Con estas 4 líneas de abajo puedo ver dos cosas importantes en Power Shell,
- ... una es resolver el path relativo a un archivo, como se ve,
resolve-path .\warning.wav deja en $advertencia el path del archivo warning.wav, dentro del directorio en el que estamos trabajando. - ... la segunda, es como escuchar un sonido de un archivo wav
$advertencia = resolve-path .\warning.wav $sound = New-Object System.Media.SoundPlayer $sound.soundLocation = $rango $sound.Play()
Hacer sonar algunos sonidos del sistema...
[System.Media.SystemSounds]::Asterisk.Play(); [System.Media.SystemSounds]::Beep.Play(); [System.Media.SystemSounds]::Exclamation.Play(); [System.Media.SystemSounds]::Hand.Play(); [System.Media.SystemSounds]::Question.Play();
Búsqueda rápida en Power Shell
Problema
Se debe hacer una búsqueda en power shell en una gran cantidad de datos, digamos un archivo de texto con 200 mil registros, de a uno por línea. La búsqueda común en powershell tarda mucho.Solución
Se realiza la búsqueda utilizando ArrayLists (System.Collections.ArrayList)clear #leo el archivo $db = get-content miArchivo
#cargo el contenido del archivo en un ArrayList [System.Collections.ArrayList] $list = New-Object System.Collections.ArrayList
foreach ($item in $db){ [void] $list.Add($item) }
#ordeno el archivo (sin esto no funciona la búsqueda binaria) $list.Sort() $reg = Read-Host "Ingrese el registro a buscar" $pos = $list.BinarySearch($reg) if ($pos -ge 0){ Write-Host "El registro se encuentra en la posición: " + $pos }else{ Write-Host "No se encuentra el registro" }
Más info en:
ArrayList (sort)
Etiquetas:
binaria,
búsqueda,
Power Shell,
PowerShell,
rápida
viernes, 3 de mayo de 2013
Problema de permisos Power Shell
Al tratar de ejecutar un power shell por primera vez suele tirar algunas veces
El problema se soluciona abriendo la consola power shell con usuario administrador y corriendo las siguientes líneas
Ambas solicitan confirmación.
File cannot be loaded because the execution of scripts is disabled on this system. Please see "get-help about_signing" for more details.
El problema se soluciona abriendo la consola power shell con usuario administrador y corriendo las siguientes líneas
Set-ExecutionPolicy Unrestricted
Set-ExecutionPolicy RemoteSigned
Ambas solicitan confirmación.
viernes, 19 de abril de 2013
Tips Windows
Links simbólicos en windows 7
Ahora windows permite tener links simbólicos al estilo linux, un gran avance... como crearlos:mklink /D origen destino
El /D se usa para crear un "directorio" simbólico... no se usa /D para crear links a archivos.
viernes, 5 de abril de 2013
Algunas cosas sobre el comando sc
Crear y eliminar servicios en windows desde línea de comandos.
El comando sc, sirve para, entre otras cosas instalar y desinstalar servicios...Por ejemplo para instalar
sc create nombre_de_mi_servicio binPath= path_del_exe start= auto
Prestar atención a que después de binPath= hay un espacio en blanco y despues el path, así se ponen los parametros, dejando un espacio en blanco, sino no funciona (loquísimo!), igual en start= auto y los demás...
Para eliminar el servicio
sc delete nombre_de_mi_servicio
También hay otros parámetros como start , para iniciar el servicio, stop para detenerlo, y el más útil "sc help" nos da la ayuda sobre SC...
Nota:
Cuando estaba probando instalar mi servicio, tuve que instalarlo y desinstalarlo varias veces con distintos parámetros. Pero me pasaba que una vez desinstalado, cuando quería reinstalarlo me tiraba el siguiente mensaje de error:The specified service has been marked for deletion.
... y no me instalaba el servicio nuevamente.
A poco de probar descubrí que la "culpa" de ese error la tenía la consola de servicios de windows (ctrl-alt-del -> start task manager -> solapa Services -> botón Services), mientras estaba abierta tira ese error, cuando la cierro el error deja de ocurrir.
Etiquetas:
instalar,
pc,
pcs,
programación,
windows
jueves, 4 de abril de 2013
Usar FunsionInventory-Agent con OCSInventory
Bueno, vamos a suponer que no tenemos instalado el OCSInventory y decidimos instalarlo
Y listo... ya tenemos nuestro agente FusionInventory-Agent funcionando contra un servidor OCSInventory.
Instalación de OCSInventory server(Debian linux)
- Bajamos la última versión del servidor de www.ocsinventory-ng.org (al momento que escribo la 2.0.5) y la descomprimimos en alguna carpeta.
- Ejecutamos el archivo setup.sh, el mismo nos guiará paso a paso en toda la instalación.
- Una vez terminado de ejecutar correctamente setup.sh, la instalación continúa por web en http://localhost/ocsreports, seguimos configurando por ahí hasta que se terminan correctamente todos los pasos y no tire ningún error por web.
Cómo hacer para que el FusionInventory-Agent funcione con el servidor OCSInventory.
Del lado del servidor debemos hacer un par de cambios...- En primer lugar ir al archivo /etc/apache2/conf.d/z-ocsinventory-server.conf y poner ésta línea
PerlSetEnv OCS_OPT_EXT_USERAGENTS_FILE_PATH /etc/ocsinventory/agents.txt - en su última parte (/etc/ocsinventory/agents.txt) indica la ubicación de un archivo de configuración que debemos crear...
- El archivo z-ocsinventory-server.conf podría llamarse ocsinventory-server.conf o de otra forma, de acuerdo a lo que haya configurado al instalar el OCSInventory Server.
- Crear el archivo /etc/ocsinventory/agents.txt (usar el path que hayamos indicado en la configuración del paso anterior).
- Este archivo de texto debe tener los nombres de los agentes de Fusion Inventory que pueden conectarse al servidor, incluyendo su versión, por ejemplo, su contenido podría ser:
FusionInventory-Agent_v2.1.7-2 FusionInventory-Agent_v2.0.6 FusionInventory-Agent_v2.2.3 FusionInventory-Agent_v2.2.7-3
^ Presten atención al formato, se agreta el "_v2" etc... - Para ver la versión del agente, en la máquina cliente se ejecuta, desde consola de comando (ej en windows):
C:\Program Files\FusionInventory-Agent-GLPI\perl\bin>perl.exe fusioninventory-agent -v
Y listo... ya tenemos nuestro agente FusionInventory-Agent funcionando contra un servidor OCSInventory.
Etiquetas:
Debian,
fusion inventory,
fusion inventory agent,
GLPI,
instalar,
inventario,
OCSInventory
martes, 26 de febrero de 2013
Tips Graphite
Eliminar gráficas
Si queremos eliminar métricas realizadas en nuestro graphite, es muy fácil...Los datos de las gráficas quedan en
/opt/graphite/storage/whisper/
...De donde los podemos borrar directamente. Validar los esquemas
Graphite nos dá una herramienta para validar que nuestros archivos de schema estén bien formados, la misma se encuentra en/opt/graphite/bin/validate-storage-schemas.py
Resulta muy útil para estar seguros de no tener errores en nuestros schemas.
Resetear Carbon
Es necesario hacer un restart al Carbon después de haber cambiado los archivos conf
/opt/graphite/bin/carbon-cache.py start
Sincronizar database
sudo /opt/graphite/webapp/graphite/python manage.py syncdb
jueves, 10 de enero de 2013
Mouse click en PowerShell
Tuve que recorrer media internet para encontrar finalmente como hacer un click del mouse con Power Shell sin tener que usar otros programas externos. Así que acá finalmente pude armar una función que hace clicks del mouse en la posición indicada de la pantalla...
# Ejecuta un click del mouse function MouseClick ($Button = "left", $x, $y, $cant = 1){ $signature = @' [DllImport("user32.dll",CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)] public static extern void mouse_event(long dwFlags, long dx, long dy, long cButtons, long dwExtraInfo); '@ [Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point($x, $y); $SendMouseClick = Add-Type -memberDefinition $signature -name "Win32MouseEventNew" -namespace Win32Functions -passThru for ($i = 1; $i -le $cant; $i++){ if($Button -eq "left"){ $SendMouseClick::mouse_event(0x00000002, 0, 0, 0, 0); $SendMouseClick::mouse_event(0x00000004, 0, 0, 0, 0); } if($Button -eq "right"){ $SendMouseClick::mouse_event(0x00000008, 0, 0, 0, 0); $SendMouseClick::mouse_event(0x00000010, 0, 0, 0, 0); } if($Button -eq "middle"){ $SendMouseClick::mouse_event(0x00000020, 0, 0, 0, 0); $SendMouseClick::mouse_event(0x00000040, 0, 0, 0, 0); } } }
Etiquetas:
Power Shell,
PowerShell,
programación,
script,
software
lunes, 7 de enero de 2013
Tips PowerShell
- Para ejecutar desde la consola DOS usar: powershell <path del script> o bien powershell .\nombre_del_script.ps1 en caso que esté en el mismo directorio.
- Los comentarios dentro de los script se inician con numeral (#)
- Algunas funciones útiles
- Escribir texto en colores por la consola DOS:
- Escribir una línea en color: Write-Host "Texto rojo en fondo verde" -foregroundcolor red -backgroundcolor green
- Cambiar los colores de la consola: $HOST.UI.RawUI.BackgroundColor = "Black"
$HOST.UI.RawUI.ForegroundColor = "Red" - Para detener la ejecución del programa: Start-Sleep -m 10000 si se usa -m se refiere a milisegundos, si se quieren usar segundos se usa -s (ej Start-Sleep -1 10 es equivalente al ejemplo anterior)
- Para concatenar strings se usa el signo
+ Para invocar programas se usa &, por ejemplo & "C:\Program Files\Winamp\winamp.exe" abrirá el winamp. o bien $winamp = "C:\Program Files\Winamp\winamp.exe"
& $winampPara escribir comandos multilínea se usa el acento invertido `, ejemplo
$msg = "mi mensaje empieza en esta línea " + [Environment]::NewLine `
+ "... y sigue en esta segunda línea"[Environment]::NewLine es el caracter de nueva línea Apagar y reiniciar Stop-Computer para apagar la computadora Restart-Compute para reiniciar Ambos se pueden usar con la opción -computer "nombrepc1, nombrepc2, nombreotrapc, etc " -force para apagar o reiniciar computadoras que se encuentren en la red. Operaciones con archivos Borrar: Remove-Item c:\borrame.txt Copiar: Copy-Item Origen Destino Escribir en archivo: "escribime en archivo" > c:\archivo.txt Operadores de comparaci ón -eq: igual -ne: distinto -gt: mayor -ge: mayor o igua -lt: menor -le: menor o igual -like: comparacion entre caracteres -notlike: -like negado -match: Que machee el segundo operando -notmatch: -match negado Operadore lógicos -and: and lógico -or: or lógico -not: not lógico Finalizar la ejecución del programa: exit Variables de error (PowerShell utiliza varias variables globales para guardar estados de error y otras informaciones importantes) aquí algunas: $? contiene el estado de ejecución de la última operación. True indica que todo salio Ok, false indica que hubo error o ejecución parcial (se basa en el exit code de los programas windows, un exit code 0 debería indicar que todo termino ok, cualquier valor distinto de 0 indicaría error, pero no todos los programas respetan esta convención, ver $LASTEXITCODE). $LASTEXITCODE guarda el código de salida de la ejecución de la última operación, sirve para interpretar la salida de programas que no respeten la convención de exit code diferente de 0 para ejecuciones con errores o no completas (ver el punto anterior). $Error ArrayList de los errores ocurridos en la sesion, los nuevos errores se agregan al principio del arraylist, dejando el último error en posición 0. Otras $true es true $false es false $null es un objeto null $_ el objeto actual (por ejemplo en un foreach-object o en un where-object, etc) Para obtener la fecha y hora: get-date -format u
Try, catch, finally en PowerShell
Acá les dejo un ejemplo de try - catch - finally en powerwhell que me fue de utilidad
:-)
try { $ErrorActionPreference = "Stop"; #esto se hace para que stopee en los errores Copy-Item file_origin file_dest #copio un archivo }catch{ Write-Host $Error[0].exception # muestro el mensaje de error $ErrorActionPreference = "Continue"; #vuelvo a setear la acción por defecto en los errores Exit # Termino la ejecución si hubo error }finally{ $ErrorActionPreference = "Continue"; #vuelvo a setear la acción por defecto en los errores }
:-)
Etiquetas:
Power Shell,
PowerShell,
programación,
software
Power Shell - ¿Cómo llamar a una función que está en otro script?
Bueno, acá explico como llamar desde un script PowerShell (ps1) a una función que se encuentra en otro script...
Supongamos que tenemos los script funciones.ps1 y principal.ps1, siendo:
funciones.ps1:
Para llamar a la funcion test desde principal.ps1 se hace
En el ejemplo estoy llamando al script de forma relativa, suponiendo que están en el mismo directorio, si no fuera así habría que hacer algo tipo ". C:\<path del script funciones.ps1>\funciones.ps1...
Espero que les sea de utilidad....
Supongamos que tenemos los script funciones.ps1 y principal.ps1, siendo:
funciones.ps1:
Function test(){ Write-Host "Dentro de la funcion" }
Para llamar a la funcion test desde principal.ps1 se hace
. .\funciones.ps1 # acá incluyo al script funciones.ps1 # notar que hay un espacio entre . y .\funciones.ps1 #luego llamo a la función test
En el ejemplo estoy llamando al script de forma relativa, suponiendo que están en el mismo directorio, si no fuera así habría que hacer algo tipo ". C:\<path del script funciones.ps1>\funciones.ps1...
Espero que les sea de utilidad....
Etiquetas:
Power Shell,
PowerShell,
programación,
script,
software
Suscribirse a:
Entradas (Atom)