mercredi 15 août 2012

le verbe "GET" dans les fonctions et les cmdlets

salut,

le verbe "GET" est l'un des verbes autorisés dans le nommage des fonctions et cmdlets
Get-Verb -verb get
on peux omettre ce verbe pour toutes les cmdlets et fonctions:
childitem c:\
psdrive
hotfix
sauf les cmdlets get-command et get-process ne supportent pas cette omission parceque le mot "process" est un mot reservé (help keywords) et "command" est vu par powershell comme etant le vieux shell "command.com" il est à noter aussi que les fonction ayant comme nom un mot reservé seront traiter comme étant des mots reservés et non pas comme étant des fonctions
man key | Select-String "\s{5,}about_*"
et s'il s'agissait d'un nom d'un executable alors l'interpréteur powershell traitera cette fonction omme étant une commande externe et non pas une fonction
function get-cmd {1}

ou bien:

function get-Function {1}
le revert de la médaille dans tout ça et qu'on ne pourra plus bénéficier de la puissance de la complétion de powershell
Service -n[TAB] alg
un autre désavantage de l'utilisation de ces commandes sans le verbe "GET", est que parfois avec la commandes get-help on se retrouve devant des resultats inatendus
PS D:\> help verb

NOM
    Write-Verbose
...
.....
voici une petite fonction qui s'appuie sur les mots reservé et teste si une commande est valide ou pas:
#############################################################
#
#  PS D:\> Test-CommandValidation -command get-process | fl
#            VerbNounConvention : True
#            ReservedKeyWords   : True
#            VerbConvention     : True
#
#############################################################
function Test-CommandValidation {
   param($Command)
   $keys = man key | 
             Select-String "(\S+)(?=\s{5,}about_*)" | 
                  select -expand Matches | 
                        select -expand value
   $verbNounConvention = $verbconvention = $reservedkeywords = $false
   $verb,$noun = $Command.Split('-')
   if($noun) {
      $verbNounConvention = $true
      if( (get-verb $verb) ) { $verbconvention = $true } 
      if($keys -contains $noun) { $reservedkeywords = $true }
   }
   else {
       $reservedkeywords = $verbconvention = $null
   }
    new-object PSObject -prop @{
       VerbNounConvention = $verbNounConvention
       VerbConvention = $verbconvention
       ReservedKeyWords = $reservedkeywords
    }
}


mardi 17 juillet 2012

Watch-Process

salut,

Parceque la gestion des processus est vitale dans la vie d'un administrateur, powershell nous a offert 5 cmdlet complémentaires:

                   
Get-Process
Stop-Process        
Wait-Process 
Debug-Process
Start-Process      
le visionnage des process se fait simplement par "Get-Process" l'idéee de Watch-Process est d'étendrre les capacitées de 'Get-Process' pour monitorer un ou plusieurs process par un intervalle de temps personnalisable, en local ou à distance:

function Watch-Process {
<#

.ForwardHelpTargetName Get-Process
.ForwardHelpCategory Cmdlet

#>
[CmdletBinding(DefaultParameterSetName='Name')]
param(
    [Parameter(ParameterSetName='Name', Position=0, ValueFromPipelineByPropertyName=$true)]
    [Alias('ProcessName')]
    [ValidateNotNullOrEmpty()]
    [System.String[]]
    ${Name},

    [Parameter(ParameterSetName='Id', Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
    [Alias('PID')]
    [System.Int32[]]
    ${Id},

    [Parameter(ValueFromPipelineByPropertyName=$true)]
    [Alias('Cn')]
    [ValidateNotNullOrEmpty()]
    [System.String[]]
    ${ComputerName},

    [ValidateNotNull()]
    [Switch]
    ${Module},
   
     [Switch]
     ${Continous},
    
     [int32]
     ${Seconds}=0,

    [Alias('FV','FVI')]
    [ValidateNotNull()]
    [Switch]
    ${FileVersionInfo},

    [Parameter(ParameterSetName='InputObject', Mandatory=$true, ValueFromPipeline=$true)]
    [System.Diagnostics.Process[]]
    ${InputObject})

begin
{
    try {
        $outBuffer = $null
        if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
        {
            $PSBoundParameters['OutBuffer'] = 1
        }
       
        $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Management\Get-Process', [System.Management.Automation.CommandTypes]::Cmdlet)
        'Seconds','Continous' | foreach { $null=$PSBoundParameters.Remove($_) }
        $scriptCmd = {& $wrappedCmd @PSBoundParameters }
        $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
        $steppablePipeline.Begin($PSCmdlet)
    } catch {
        throw
    }
}

process
{
       if($Continous) {
          while($true) {
              Start-Sleep -Seconds $Seconds
              Get-Process @PSBoundParameters
          }
       }
     
        try {
            $steppablePipeline.Process($_)
        } catch {
            throw
        }
}

end
{

    try {
        $steppablePipeline.End()
    } catch {
        throw
    }
}

}
on peux l'utiliser ainsi:
PS> Watch-Process -Name n* -Continous -Seconds 2
PS> Watch-Process note*
PS> Watch-Process -Name n* -Continous

jeudi 3 mai 2012

String.Match( why not ? )

salut, l'un des points fort de PowerShell c'est son extensibilité et sa flexibilité, prenons par exemple, les fichiers de configuration de types étendus, ces fichiers permettent d'ajouter des membres dynamiques ou statiques aux objets telques des propriétés ou des méthodes,..etc l'ajout de ces membres ce fait grâce à la cmdlet Update-TypeData qui va charger notre fichier de configuration en mémoire puis ajoutera nos membres dans la session active. voici un petit exemple:


    
        System.String
        
            
                Matches
                
            

           
                Match
                
            

        
    

ce fichier de configuration va ajouter au type system.string deux nouvelles méthodes Match et Matches la première méthode va matcher la première reference de la chaine de caractères, et la deuxième va matcher toutes les références trouvée.. voius devez avant tout charger ce fichier en mémoire:
PS> Update-TypeData MyType.ps1xml
ensuite on pourra faire des choses du genre:
PS> # premier test
PS> Get-Content file.txt | foreach { $_.matches('KB\d{5,}') }
PS>
PS> $s = 'aeejkdkk55d'
PS> $p = '^.'
PS> $s.Match($p)
PS>

mercredi 4 avril 2012

le pipeline... comment en tirer profit ?

salut, l'une des plus belle choses dans powershell est son méchanisme révolutionnaire de pipeline et plus précisemment le méchanisme de liaison entre la sortie d'une commande et l'entrée d'une autre commande , en fait powershell permet de lier entre la valeur et/ou la propriété de l'objet de sortie avec le(s) paramètres de la commande d'entrée...ceci va nous permettre non seulement de rendre le pipeline entre les commandes "fluide" et "puissant" mais aussi de construire nos propres objets personnalisés si la liaison entre les commandes du pipeline n'est pas "permise" on va prendre un exemple facile...nous avons un fichier machines.txt contenant le nom de quelques machines:
C:\> cat ./machines.txt

win8
srv-9
localhost
nous voulons parcourir tous ces posts et afficher tous les services en marche pouvant être stopper...nous avons deux méthodes pour traiter ce problème 1- la façon "traditionnelle" 2- la façcon "powershell way" 1- la façon traditionnelle: pas de magie, c'est verbeux déclaratif et surtout fastidieux pour les tâches rapides d'administrations.
$computers=cat ./machines.txt
foreach($computer in $computers) {
  get-service -computer $computer | where {$_.status -eq 'running' -and $_.canstop -eq $true}
}
2- powershell way: c'est magique, concit, direct et rapide à écrire:
cat ./machines.txt | ConvertFrom-Csv -h 'computername' | gsv | ? {$_.status -eq 'running' -and $_.canstop}
tout le secret reside dans le méchanisme de binding entre les commandes: get-service à un paramètre "-computerName" et il accepte l'entrée du pipeline en mode "BypropertyName" tout ce qu'on fera par la suite c'est de générer un objet ayant comme propriété 'computerName' et ...c'est tout..c'est pas magique ça

samedi 31 mars 2012

Clear-PSSession : comment nettoyer notre environement

salut, les "entités" qui prennent de la place dans la mémoires comme les fonctions-filtres-variables-alias-modules-psessions-..etc peuvent parfois encombré notre session..pour remedier à ce problème voici une petite fonction 'Clear-PSSession' qui permet de nettoyer complètement notre environement et en plus s'auto-charge automatiquement:
if($Host.Name -ne 'ConsoleHost') {
  write-error "ce module ne fonctionne que sous le terminal powershell"
  return
}

$Script:CurrentProcess = $pid
$Script:MyCmd = $MyInvocation.MyCommand.Definition

function Clear-PSSession {
   powershell -noexit -c "stop-process $($Script:currentProcess);import-module '$($Script:MyCmd)'"
}

Export-ModuleMember -Function *  
exemple d'utilisation:

PS> $a = 1
PS> function foo {1}
PS> foo
1
PS> Import-Module .\psession.psm1
PS> gcm -Module psession


CommandType     Name                                                Definition
-----------     ----                                                ----------
Function        Clear-PSSession                                     ...



PS> Clear-PSSession
PS> foo
Le terme « foo » n'est pas reconnu comme nom d'applet de commande, fonction, fichier de script ou prog
 Vérifiez l'orthographe du nom, ou si un chemin d'accès existe, vérifiez que le chemin d'accès est cor
.
Au niveau de ligne : 1 Caractère : 4
+ foo <<<<
    + CategoryInfo          : ObjectNotFound: (foo:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException


PS> $a
PS>

samedi 10 mars 2012

Get-WMIHelp : un Get-Help pour WMI

salut, dans le post précédent, la fonction Get-WMIHelp nous permettait une aide afficher dans la console..dans ce post on va rendre cette aide plus conviviale.. voici la nouvelle fonction
function Get-WMIHelp {  
  <#
.SYNOPSIS

  Affiche des informations sur les classes et propriétés WMI

.DESCRIPTION

  Affiche des informations sur les classes et propriétés WMI

.PARAMETER InputObject

Spécifie un objets  représentant l'objet à récupérer. Entrez une variable contenant l'objets, ou tapez une commande ou une expression permettant d'obtenir cet objet. Vous pouvez également diriger un objet
  vers Get-WMIHelp. 
 
 .PARAMETER Class
 Spécifie le nom d'une classe WMI
 
.PARAMETER Path
 
 Spécifie le chemin d'accès de l'emplacement où le fichier de sortie éléments doit être copiés.

.EXAMPLE

PS C:\> Get-WmiObject -List win32_Bios | Get-WMIHelp

Cette commande obtient toutes les données disponibles sur les paramètres de la classe WMI 'win32_Bios'


.EXAMPLE

PS C:\> Get-WMIHelp -InputObject ([WMIClass]'win32_process')

.EXAMPLE

PS C:\> $WMI = Get-WmiObject -List win32_share
PS C:\> Get-WMIHelp -InputObject $WMI -Path Z:\shareinfo.htm

 La première commande obtient les méta données de la classe WMI 'win32_share', puis elle les stocke dans la variable $WMI.
 La deuxième commande utilise le paramètre InputObject pour passer l'objet  qui est stocké dans la variable $WMI à la fonction Get-WMIHelp. 
 Le paramètre 'Path' permet de spécifier un chemin pour stocké notre fichier "htm"


.EXAMPLE

PS C:\> Get-WMIHelp -Class "win32_OperatingSystem" -path c:\os.htm

 
.LINK
about_WMI_Cmdlets
Get-WmiObject

.INPUTS
System.Management.ManagementClass

.NOTES

   Author: Walid Toumi
   Blog: http://walidtoumi.blogspot.com
   Date: 2/28/2012
   Keywords: WMI - Get-WmiObject - Help
#>
  [CmdletBinding(DefaultParameterSetName='InputObject')]
  param(
   [Parameter(
     ValueFromPipeLine=$True,
     Mandatory=$True,
     Position=0,
     ParameterSetName='InputObject')]
   [ValidateNotNullOrEmpty()]
   [System.Management.ManagementClass]
   ${InputObject},
   [Parameter(Position=0,ParameterSetName='class')]
   ${Class},
   [System.String]
   ${Path})
 
  Try{ 
       switch ($PSCmdlet.ParameterSetName) {
        "Class" {
           $null=Get-WmiObject -Class $Class -ea 'stop'
           $IS_WMI_CLASS = $Class
         }
        "InputObject" {
              $IS_WMI_CLASS = $InputObject.__CLASS
         }
       }
       $WMIClass = Get-WmiObject -List $IS_WMI_CLASS -Amended
       $Desc = $WMIClass.Qualifiers['Description']
       $WMIProperties = $WMIClass.PSbase.Properties
       $Head=@"
     
"@
     $Body = @"
    

WMI CLASS

$($WMIClass.__Class)

WMI CLASS DESCRIPTION

$($Desc.Value)

PARAMETERS

"@ $WMIHelp = $WMIProperties | ForEach-Object { $desc = $($WMIClass.psbase.Properties["$($_.Name)"]).Qualifiers['Description'] New-Object PSObject -Property @{ Description = $desc.value Type = $_.Type Name = $_.Name } } <# end foreach #> | ConvertTo-Html -Property name,Type,description -Head $Head -Body $Body } catch { Write-Error $_ } finally { $WMIHelp > $env:TEMP\wmihelp.htm if($Path) { Try{ Move-Item $env:TEMP\wmihelp.htm $Path -ea 'stop' } catch { Write-Error $_ } } # end if else { Invoke-Item -Path $env:TEMP\wmihelp.htm } # end else } # end finally }

mardi 28 février 2012

invoke-item hklm:\softawre est-ce possible ?

Salut, parfois on est confronté devant des cas ou l'affichage des données dans le prompt n'est plus adéquate, pour cette raison l'equipe de developpeur de PS nous a fourni une cmdlet spécial du nom 'invoke-item' cette cmdlet, nous permet d'executer des actions sur les objets, tel que: * ouvrir le fichier 'a.txt' avec l'application qui lui est associée * ou bien "ouvrir le dossier 'c:\tree'" * ou bien "ouvrir tous les fichiers qui commencent par 't' et qui se termine par 'txt'" cette cmdlet est plus complète que la commande 'start' parcequ'elle permet l'utilisation des wildcards et permet de filtrer les élements selon certains critères. malheureusement cette cmdlet n'est pas suporter par le psprovider 'Registry' .... si on fait une chose du genre:
PS Walid2mi>> Invoke-Item HKCU:\Software
ça va nous retourner une erreur:
Invoke-Item : L'exécution du fournisseur s'est arrêtée, car le fournisseur ne prend pas en charge cette opération.
comme vous venez de constatez, le 'Registry' n'est pas le même environement que le 'FileSystem' une des solutions possibles est de créer notre propre fonction 'Invoke-Registry' qui va nous permettre d'afficher le registre sur la clef qu'on entrera comma paramètre...voici la fonction
function Invoke-Registry {

<#
.SYNOPSIS
   affiche le registre sur la clef spécifié
   
.DESCRIPTION
   affiche le registre sur la clef spécifié
 
.PARAMETER Path
Spécifie le chemin d'accès de la clef de registre sélectionné

.PARAMETER Maximize
maximize la fenêtre du registre
 
.EXAMPLE
   PS HKLM:\Softawre> invoke-Registry .
 
.EXAMPLE
   PS C:\> Invoke-Registry -Path 'Registry::\HKEY_Classes_Root\txtfile'
 
.EXAMPLE
   PS C:\> Invoke-Registry HKCU:\Environment -Max
 
.LINK
 invoke-item

.INPUTS
 none
vous ne pouvez pas diriger des objets pour cette fonction 

.OUTPUTS
 none 

.NOTES
   Author: Walid Toumi
   Blog: http://walidtoumi.blogspot.com
   Date: 2/28/2012
   Keywords: Registry - Invoke-Item
#>
    param(
      [Parameter(Mandatory=$true)]
      [ValidateScript({
             if(((item $_).PSProvider.Name -eq 'Registry') -or $_ -eq '.') 
             {$true} else {throw 'le paramètre "Path" doit correspondre à une clef de registre valide'}})]
        $Path,
      [Switch]$Maximize)
       try{
            $ErrorActionPreference = 1
            $key = (Get-Item $Path).Name
            $item = get-itemProperty HKCU:\Software\Microsoft\Windows\CurrentVersion\Applets\Regedit -Name lastkey
            $item.LastKey = "My Computer\$key"
            Set-ItemProperty -Path $item.PSPath -Name lastkey $item.LastKey
            if($Maximize) { invoke-expression "$env:comSpec /c start /max regedit.exe" } else { regedit.exe }
       } 
       catch {
            Write-Error $_.Exception.message
        }
       finally{
           $ErrorActionPreference = 2
       }
}
cette solution n'est peux être pas la plus optimale, mais elle fonctionne. si je trouve un peux de 'temps' et de 'paix'...ces jours-ci...je pourrais même envisagé de créer une fonction proxy du cmdlet 'invoke-item' qui utiliserait cette technique.. à bientôt alors...que la paix soit avec nous! ;)

lundi 2 janvier 2012

fonction qui affiche et sélectionne les fichiers à la volée

salut,

il y a des fois, la recherche de fichiers dans un répertoire contenant des centaines voire des milliers d'autres fichiers, soit une tâche fastidieuse...ça sera sympa d'avoir une petite fonction qui fait ceci à notre place et en plus sélectionne notre fichier à la voilée, non :)
Function Select-File {
 
  [CmdletBinding()]
  Param(
    [Parameter(Mandatory=$True)]
    [ValidateScript({ 
             if(Test-Path $_) {$true}
             else {
               throw $("fichier ""$_"" introuvable")
             } 
    })]
    [System.String]$FilePath
  )
  Begin{
      $item=get-item $FilePath
      Start-Process -f explorer.exe -a "/select,""$($item.FullName)"""
  }
}

on peux utiliser cette petite fonction ainsi:
PS> Select-File c:\fichier.txt
EDIT: la fonction ne peux pas être utiliser comme un filtre

dimanche 27 novembre 2011

get-content peux désormais traiter les fichiers XML



salut, pour eviter de caster tout le temps les fichiers xml en [Xml] à fin de les traiter j'ai ajouté deux nouveaux paramètres à 'get-content' AsXml et XPath pour que le traitement soit direct.
Function Get-Content {
<#
***************************************************************************
 
 --------------------8<-----------------------------------------
    Ajout de deux nouveaux paramètres pour simplifier
    le traitement des fichiers XML: [-AsXml] [-XPath ]
    
    Attention: l'expression Xpath est sEnSiBlE à La cAsSe
    
                                  Walid toumi             
 --------------------8<-----------------------------------------
 
 PS> # Exemples d'utilisation:
 
 PS> $file = "$PSHOME\types.ps1xml"
 
 PS> $u = cat $file -As | Select-Xml -XP "//ScriptProperty" | Select -Expand Node
 PS> $u

 PS> $Xml = Get-Content $file -AsXml
 PS> $Xml.Types.Type[1..10]
 
 PS> Get-Content $file -AsXml -XPath "//Type[contains(Name,'Xml')]/Name"
 
 **************************************************************************
 
.ForwardHelpTargetName Get-Content
.ForwardHelpCategory Cmdlet

#>

[CmdletBinding(DefaultParameterSetName='Path', SupportsTransactions=$true)]
param(
    [Parameter(ValueFromPipelineByPropertyName=$true)]
    [System.Int64]
    ${ReadCount},

    [Parameter(ValueFromPipelineByPropertyName=$true)]
    [System.Int64]
    ${TotalCount},

    [Parameter(ParameterSetName='Path', Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true)]
    [System.String[]]
    ${Path},

    [Parameter(ParameterSetName='LiteralPath', Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true)]
    [Alias('PSPath')]
    [System.String[]]
    ${LiteralPath},

    [System.String]
    ${Filter},

    [System.String[]]
    ${Include},

    [System.String[]]
    ${Exclude},
    
    [System.String]
    ${XPath},

    [Switch]
    ${Force},
    
    [Switch]
    ${AsXml},

    [Parameter(ValueFromPipelineByPropertyName=$true)]
    [System.Management.Automation.PSCredential]
    ${Credential})

begin
{
    try {
        $outBuffer = $null
        if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
        {
            $PSBoundParameters['OutBuffer'] = 1
        }
        $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Management\Get-Content', [System.Management.Automation.CommandTypes]::Cmdlet)
        $cmd = ''
         if($AsXml) {
          [void]$PSBoundParameters.Remove('AsXml')
          $cmd += ' | ForEach-Object {$fx=@()} {$fx+=$_} {$fx -as [Xml]}'
            if($XPath) {
               [void]$PSBoundParameters.Remove('XPath')
               $cmd += ' | Select-Xml -XPath $XPath | Select -expand Node'
            }
        } 
        $ScriptCmd = [ScriptBlock]::Create(
           { & $wrappedCmd @PSBoundParameters }.ToString() + $Cmd
          )
        $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
        $steppablePipeline.Begin($PSCmdlet)
    } catch {
        throw
    }
}

process
{
    try {
        $steppablePipeline.Process($_)
    } catch {
        throw
    }
}

end
{
    try {
        $steppablePipeline.End()
    } catch {
        throw
    }
}

}



dimanche 20 novembre 2011

Get-ChildItem un peu plus conviviale :)

Salut, je ne sais pas si quelqu'un d'autre a eu l'idée d'ajouter ces deux fonctionnalités à la cmdlet 'Get-ChildItem' et je n'ai pas aussi tester Powershell vNext pour voir s'il implémente l'une de ces deux fonctionnalités... alors, je me suis dit pourquoi attendre ?! j'ai tout ce qu'il me faut pour configurer mes 'cmdlets' .... alors la première chose qui m'ai venu à l'esprit c'est d'ajouter deux nouveaux paramètres: 'FileSizeInHumanReadableFormat' et 'Pattern' le premier est une implémentation du switch '-lh' de la commande lunix 'ls' qui signifie "Display File Size in Human Readable Format" et l'autre paramètre pour allez un cran au-dessus des simples wildcards utiliser par les "filter" et "include" ... 'pattern' va nous permette d'utiliser les RegExp dans nos recheches :) vous pouvez voir les nouveaux paramètres de la fonction 'Get-ChildItem' en écrivant ceci:
Get-Command Get-ChildItem -TotalCount 1 -Syntax  
en fait le méchanisme d'execution des commandes dans "Windows Powershell"
help Precedence
va nous permettre d'executer notre fonction avant le cmdlet 'Get-Childtem'

Function Get-ChildItem {
<#

.ForwardHelpTargetName Get-ChildItem
.ForwardHelpCategory Cmdlet

#>

[CmdletBinding(DefaultParameterSetName='Items', SupportsTransactions=$true)]
param(
    [Parameter(ParameterSetName='Items', Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
    [System.String[]]
    ${Path},

    [Parameter(ParameterSetName='LiteralItems', Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true)]
    [Alias('PSPath')]
    [System.String[]]
    ${LiteralPath},

    [Parameter(Position=1)]
    [System.String]
    ${Filter},

    [System.String[]]
    ${Include},

    [System.String[]]
    ${Exclude},
    
    [System.String]
    ${Pattern},

    [Switch]
    ${Recurse},

    [Switch]
    ${FileSizeInHumanReadableFormat},

    [Switch]
    ${Force},

    [Switch]
    ${Name})

begin
{
    try {
        $outBuffer = $null
        if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
        {
            $PSBoundParameters['OutBuffer'] = 1
        }
        $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Management\Get-ChildItem', [System.Management.Automation.CommandTypes]::Cmdlet)
        $cmd = ""
        if($FileSizeInHumanReadableFormat) {
          $PSBoundParameters.Remove('FileSizeInHumanReadableFormat') | Out-Null
          $cmd = @"
            | ForEach-Object {
                `$_length=Switch(`$_.length) {
                  { `$_ -lt 1kb } 
                           {  '{0}B' -f (`$_) ;break }
                  { `$_ -lt 1MB }
                           {  '{0}KB' -f ([math]::round(`$(`$_/ 1kb)), 2) ;break }
                  { `$_ -lt 1gb }
                            { '{0}MB' -f ([math]::round(`$(`$_/ 1mb), 2)) ;break }
                  defaut { 
                            {  '{0}GB' -f ([math]::round(`$(`$_/ 1gb), 2)) ;break }
                   }
                }
                if(`$_.PSISContainer) { `$_length=`$null }
                New-Object PSObject -Property @{
                  Mode = `$_.Mode
                  LastWriteTime = `$_.LastWriteTime
                  Length = `$_length
                  Name = `$_.Name
                }
            }         
"@
        }
        if($PSBoundParameters['Pattern']) {
          if($Filter -or $Include) {
           throw "les paramètres Pattern et Filter/Include sont mutuellemnt exculsive"
          } else {
          $PSBoundParameters.Remove('Pattern') | Out-Null
          $scriptCmd = {& $wrappedCmd @PSBoundParameters | Where { $_.Name -imatch "$Pattern"  } }
          }
        } else {
          $scriptCmd = {& $wrappedCmd @PSBoundParameters } 
        }
        $scriptCmd = $ExecutionContext.InvokeCommand.NewScriptBlock(
                $scriptCmd.ToString() + $cmd
            )
        $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
        $steppablePipeline.Begin($PSCmdlet)
    } catch {
        throw
    }
}

process
{
    try {
        $steppablePipeline.Process($_)
    } catch {
        throw
    }
}

end
{
    try {
        $steppablePipeline.End()
    } catch {
        throw
    }
}

}



voici quelques utilisation de cette fonction:
Get-ChildItem  -Path $env:windir -Pattern "^\d{2}" -FileSizeInHumanReadableFormat
Get-ChildItem -path $env:windir -filter *.txt -FileSizeInHumanReadableFormat
 
la sortie de la commande est un objet:
System.Management.Automation.PSCustomObject 
 ou
System.IO.FileSystemInfo

jeudi 10 novembre 2011

Get-Help: comment afficher l'aide graphique sans être connecté à internet

salut,

voici une petite fonction proxy du cmdlet Get-Help qui vous permettera d'avoir une aide graphique sans utilisation du paramètre "Online" (qui requiert une connexion internet)...la démarche est toute simple: On décompile à la volée le fichier d'aide local de PS puis on sélectionne la rubrique choisi par une simple recherche...


Function Get-Man {
<#

.ForwardHelpTargetName Get-Help
.ForwardHelpCategory Cmdlet

#>

[CmdletBinding(DefaultParameterSetName='AllUsersView')]
param(
    [Parameter(Position=0, ValueFromPipelineByPropertyName=$true)]
    [System.String]
    ${Name},

    [System.String]
    ${Path},

    [System.String[]]
    ${Category},

    [System.String[]]
    ${Component},

    [System.String[]]
    ${Functionality},

    [System.String[]]
    ${Role},

    [Parameter(ParameterSetName='DetailedView')]
    [Switch]
    ${Detailed},

    [Parameter(ParameterSetName='AllUsersView')]
    [Switch]
    ${Full},

    [Parameter(ParameterSetName='Examples')]
    [Switch]
    ${Examples},

    [Parameter(ParameterSetName='Parameters')]
    [System.String]
    ${Parameter},
    
    # affiche l'aide dans le navigateur par defaut
    [Switch]
    ${ShowUI},

    [Switch]
    ${Online})

begin
{
    try {
        $outBuffer = $null
        if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
        {
            $PSBoundParameters['OutBuffer'] = 1
        }
        $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Get-Help', [System.Management.Automation.CommandTypes]::Cmdlet)
        if($PSBoundParameters['ShowUI']) {
          $null=$PSBoundParameters.Remove('ShowUI')
                
    function invokeUI {
         param(
           [Parameter(ValueFromPipeLineByPropertyName=$True)]
           $Name
         )
        Begin{
             $HelpChm = "$env:Windir\Help\WindowsPowerShellHelp.chm"
             $HelpTmp = "$env:Temp\PSCmd"
             if (! (Test-Path $HelpChm) ) { 
                  throw "le fichier source $HelpChm est introuvable"
             }
            if(! (Test-Path $HelpTmp)) {
                 Start-Process -File "hh.exe" -Arg "-decompile $HelpTmp $HelpChm" -Wait
            }
            $HtmlFiles = Get-childItem "$HelpTmp\html" *.htm
        }
        Process{
            forEach($file in @($HtmlFiles)) {
                 [Xml]$Xml = get-content $file.Fullname
                 if($Xml.html.head.title -ieq "$Name") {
                    invoke-item $file.Fullname 
                 }
            }
       }
       End{
           Remove-Item $HelpTmp -Recurse
       }
   }

        $scriptCmd = {& $wrappedCmd @PSBoundParameters | invokeUI}
        } else {
        $scriptCmd = {& $wrappedCmd @PSBoundParameters }
        }
        $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
        $steppablePipeline.Begin($PSCmdlet)
    } catch {
        throw
    }
}

process
{
    try {
        $steppablePipeline.Process($_)
    } catch {
        throw
    }
}

end
{
    try {
        $steppablePipeline.End()
    } catch {
        throw
    }
}
}

l'utilisation de Get-Man est simple voici quelques exemples:

PS>  Get-Man -Name Select-Xml -ShowUI
 
PS> Get-commend Get-Man -syntax






mercredi 24 août 2011

plage d'adresses

salut,

voici un petit script simple pour trouver une plage d'adresses entre deux IP:

    @echo off
    
    call :go 192.168.0.3 192.168.0.65
    echo %ips%
    goto :eof
     
    :go
    setlocal enabledelayedexpansion&set a=0
    for /f "tokens=1-8 delims=." %%a in ("%1.%2") do (
       set /A a=%%h-%%d,b=%%g-%%c,c=%%f-%%b,d=%%e-%%a  
       for %%e in (b c d) do (
          if !%%e! gtr 0 (set e=!e!*255) else (set e=)
       set /A a+=%%e!e!
    ))
    endlocal & set ips=%a%





comment convertir un decimal en binaire

 salut,




@echo off

set num=
set bin=
set k=

set /A num=%1,1/num 2>Nul || (
  findstr /bl "::|" %0
  exit /b 1)
::|
::| usage:  prog 
::|
::| exemple: prog 2335
::|
:lp
set /A k=num %% 2
set bin=%k%%bin%
set /A num/=2
if %num% gtr 0 goto :lp

echo  %bin%


mercredi 27 juillet 2011

Comment numéroter les lignes d'un fichier:

salut,

L'une des solutions possibles:

   @Echo >$ oFF
   Set file=c:\temp\a.txt
   for /f "delims=" %%a in ('
      "fc /l /n %file% $|findstr -vbi [\*A-Z]"
    ') do echo %%a
   del $ 
   goto:eof 




samedi 14 mai 2011

utilisation de %variable% en PS

Salut,

voici une petite fonction pouvant afficher/créer des variables d'environements aussi simple que les batchs NT


del alias:set -ea 0
function set
{
  $_nam,$_rest = "$args".Split('=')
  if(!$_rest -and $_nam) { gci "env:$($_nam)" }
  elseif(!$_nam) { gci env: }
  else {
    $_val = [environment]::ExpandEnvironmentVariables("$_rest")
    ni -pa env:$_nam -va $_val -fo
  }
}


et voici quelques exemples d'utilisation:


# affichage de toutes les variables d'environments
[1] set
Name                           Value                                           
----                           -----                                           
ALLUSERSPROFILE                D:\Documents and Settings\All Users             
APPDATA                        D:\Documents and Settings\walid2mi\Applicatio...
CLIENTNAME                     Console                                         
CommonProgramFiles             D:\Program Files\Fichiers communs   
...
...

[2] # affichage des variables commencant par "P"
[2] set p*
Name                           Value                                           
----                           -----                                           
Path                           D:\WINDOWS\system32;D:\WINDOWS;D:\WINDOWS\Sys...
PATHEXT                        .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;....
PROCESSOR_ARCHITECTURE         x86                                             
ProgramFiles                   D:\Program Files                                

[3] # création d'une variable "user"
[3] set user = %username%

[4] # création d'une variable "Home"
[4] set home=$home



mercredi 4 mai 2011

Ajouter un add-On à son éditeur ISE

Salut,

me revoilà, ce petit code permet d'ajouter à la barre de menu un nouveau menu personnalisé destiné à l'ajout des add-ons, vous pouvez inclure cette fonction dans votre profil ISE pour qu'elle se charge à chaque session démarrée.


Function Add-AddOns
{
<# 
.synopsis
 affiche et/ou créer des add-ons
.parameter List
  affiche tous les noms des add-ons disponibles
.parameter Name
  nom du add-on
.parameter ShortCut
  un raccourcis pour le add-on
.parameter Action
  un bloc de script qui va s'executer à l'appel du add-on
.example
  Add-AddOns -List
.example
 PS> Add-AddOns -n "Effacer le volet de Script" -s "ctrl+shift+b" -a {   
 >>   $psISE.CurrentFile.Editor.Clear()
 >>  }

  Créer un add-on pour effacer le volet script
.example
  PS> Add-AddOns -RemoveAll
  
  Supprime tous les add-Ons 
.example
  PS> Add-AddOns -RemoveItem 1
  
  Supprime l'add-on ayant l'index 1
.example
  PS> $sb = { Invoke-Expression 'c:\script.ps1'  }
  PS> Add-AddOns "script.ps1" "Ctrl+shift+q" $sb
  
  Execute le script 'c:\script.ps1'
#> 
  [CmdletBinding(DefaultParameterSetName='List')]
  Param(
   [Parameter(Mandatory=$False,Position=0,ParameterSetName='List')]
   [Switch]$List,
   [Parameter(Mandatory=$True,Position=0,ParameterSetName='RemoveAll')]
   [Switch]$RemoveAll,
   [Parameter(Mandatory=$True,Position=0,ParameterSetName='RemoveItem')]
   [int]$RemoveItem,
   [Parameter(Mandatory=$True,Position=0,ParameterSetName='Name')]
   [String]$Name,
   [Parameter(Mandatory=$false,Position=1,ParameterSetName='Name')]
   $ShortCut=$null,
   [Parameter(Mandatory=$True,Position=2,ParameterSetName='Name')]
   [ScriptBlock]$Action
  )
  if($Host.Name -ne 'Windows PowerShell ISE Host') 
  { throw "fonctionne uniquement dans l'environment ISE" }
  Switch ($PSCmdlet.ParameterSetName)
  {
     "List"
     {
        $Items = $psISE.CurrentPowerShellTab.AddOnsMenu.Submenus
        for($i=0;$i -le $items.count-1;$i++) 
         { Select -inp $Items @{n="Index";e={$i}},
            @{n="Name";e={$_.Item($i).DisplayName}}   
         }
     }
     "RemoveAll"
     { 
       $psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Clear() 
     }
     "RemoveItem"
     { 
       $psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.RemoveAt($RemoveItem)
     }
     "Name"
     {
       $psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add($Name,$Action,$ShortCut)
     }
  }
}



Bon Scripting  ;)




vendredi 22 avril 2011

Inclure du code PS dans un fichier Batch

salut,


;@echo off & Setlocal EnableExtensions
;echo CMD %ERRORLEVEL%
;:<>
;Findstr -rbv ; %0 | powershell -c - 
;goto:sCode ######################################
 
"PSH " | Write-Host -for yellow -no
$_=$OFS;$OFS=''
$char=87,65,76,73,68,50,77,73,64,71,77,65,73,76,46,67,79,77
([string][char[]]($char));$OFS=$_
exit 5
 
;:sCode ######################################
;:<>
;echo CMD %ERRORLEVEL%
;pause & goto :eof




voici une autre approche plus robuste:


@echo off
::::::::::::::::::::::::::::::::::::
For /f "delims=:" %%a In ('
     findstr /Bn "@PS" %0
 ') do Set /ALine=%%a
 more +%Line% %0  | powershell -c -
::::::::::::::::::::::::::::::::::::
:: ici suite du code Batch

dir
pause & exit /b 

@PS ::::::::::::::::::::::::::::::
Function Get-Test {
  param()
  Begin{
    Write-Warning "Debut du traitement" 
  }
  Process{
    write-verbose "ici n'importe quel traitement"
    gps power*,cmd*  
    <# 
      un Bloc de commentaires 
    #>
  }
  End{
   Write-warning "Fin du traitement"
  }
}
Get-Test
exit


Trier selon les Types d'objets

cette petite fonction, à pour rôle de trier selon 3 types d'objets: [String] [Version] et [int]


Function Sort-ObjectType {
<#
 .Synopsis
   Sort Object by Types
 .Description
   Sort Object by Types
 .Parameter Type
   Specifies the type of object
     - ToString:   [System.String]
     - ToInteger:  [System.Int32]
     - ToVersion:  [System.Version]
     - ToIPAddress [System.Net.IPAddress]
 .Parameter CaseSensistive
 .Parameter Descending
 .Parameter Unique    
 .Example
  [1]PS> $str += "10","2","5"
  [2]PS> $str | Sort-Object # 10 2 5
  [3]PS> $str | Sort-ObjectType -Type ToInteger # 2 5 10
 .Example
  [1]PS> '1.0.1.10','1.0.1.100','1.0.1.9' | Sort-Object -unique
  [2]PS> # 1.0.1.10 > 1.0.1.100 > 1.0.1.9
  [3]PS> '1.0.1.10','1.0.1.100','1.0.1.9' | Sort-ObjectType -Type ToVersion
  [4]PS> # 1.0.1.9 > 1.0.1.10 > 1.0.1.100
 .Example
  [1]PS> $ips="3.25.20.100","198.10.3.1","1.2.0.3","10.2.0.6"
  [2]PS> $ips | Sort-ObjectType -Type ToIPAddress 
 .Outputs
  System.String
#>
#Requires -version 2.0
 Param(
  [ValidateSet('ToString','ToInteger','ToVersion','ToIPAddress')]
  $Type,
  [Switch]$CaseSensitive,
  [SWitch]$Descending,
  [Switch]$Unique
  )
 $input | Sort-Object -Property {
    $ty=$_
    Switch($Type) {
     'ToString'  {[String]$ty}
     'ToInteger' {[Int]$ty}
     'ToVersion' {[Version]$ty}
     'ToIPAddress' { 
         [byte[]]$ty.split('.')|ForEach{[string]::Format("{0:000}",$_)}
         }
     default {$ty}
    }
  } -case:$CaseSensitive -desc:$Descending -uni:$Unique
}

jeudi 14 avril 2011

colorer vos invites de commandes

salut,

malheureusement, dans le shell windows, on n'a pas de commandes native qui permet de colorer nos chaines de caractères, pour pallier à cette lacune on peux télécharger des commandes externes, ou bien pour les puristes on peux bricoler un tuc comme ceci:


@echo off
if "%~2"=="" (
   cls
   echo.
   echo   .SYNTAXE:
   echo. 
   echo        %~n0 BackgroundColor+ForegroundColor chaine
   echo.
   echo  ------------ EXEMPLE 1 --------------
   echo.  
   echo        CMD E:\^> %~n0 0c "hello world"
   echo.
   echo  ------------ EXEMPLE 2 --------------
   echo.
   echo        CMD E:\^> type script.cmd
   echo        @echo off
   echo        call cecho ce "Debut"
   echo        echo processus
   echo        call cecho ec "Fin"
   exit /b 3
)
mkdir $temp || (exit /b 2)
pushd $temp || (rmdir $temp & exit /b 1)
for /f "delims=" %%. in ('
    "%ComsPec% /k prompt $h$h <&1"
 ') do >rtn echo %%.
Call:bfc %1 %2
popd
rmdir /s /q $temp
exit /b 0

:bfc
>%2 (set/P=+) <&1
findstr /a:%1 + %2 con
type rtn
goto :eof

supprimer les dossiers vides

salut,

voici un petit filtre en PS pour supprimer les dossiers vides


Filter Remove-EmptyFolder
{
  try{
   [IO.DirectoryInfo]$Folder=$_
   if($Folder.GetFiles().count -eq 0) {$Folder.Delete()}
  }
  catch{}
}

PS> gci -Recurse | Remove-EmptyFolder