Why is my if statement not being read properly? - powershell

I have a script that backs up a user profile from the local, or remote machine and places it onto a share: $Global:Shared_BackupPath = "\\server\share\". I've been tweaking it a little more and just ended up making some variables into Global variables (not sure if this is the issue - dont see why it would be).
This is the condition:
if(-not (Get-EventSubscriber)){
I tried changing it to -eq $null to see if it would make any difference, but it didn't.
Its just not analyzing the condition properly and goes on to display my message box before all Jobs are done: it's "supposed" to wait till there's no more events and then display the message box:
Register-ObjectEvent -InputObject $job -EventName StateChanged -Action {
#Start-Sleep -Milliseconds 500
$eventSubscriber | Unregister-Event
$eventSubscriber.Action | Remove-Job
if(-not (Get-EventSubscriber)){
$Profile_Sum = Get-ChildItem -Path $Global:BackUp_Path -Recurse |
Measure-Object -Property length -Sum |
Select-Object -ExpandProperty Sum
$Size = try{if($Profile_Sum -lt 1048576){ $TinyByte = " {0:N2}" -f ($Profile_Sum / 1KB) + " KB"; $TinyByte }
elseif($Profile_Sum -gt 1048576 -and $Profile_Sum -lt 1073741824){ $MediumByte = " {0:N2}" -f ($Profile_Sum / 1MB) + " MB"; $MediumByte }
elseif($Profile_Sum -gt 1073741824){ $GiganticByte = " {0:N2}" -f ($Profile_Sum / 1GB) + " GB"; $GiganticByte } } Catch {}
$Begin_Time = Get-Item -Path $Global:BackUp_Path | Select-Object -ExpandProperty LastWriteTime
$End_Time = Get-Date -Format G
Get-Job | Remove-Job
[System.Windows.MessageBox]::Show("Copying Complete!`nStart Time: $Begin_Time `nEnd Time: $End_Time `nProfile Size copied: $Size")
}
} | Out-Null
}
I feel like I may have an idea due to the event itself being registered as a job but, not too sure how to go about it and have it wait until its done with ALL jobs before displaying the messagebox informing me when the copying is complete. Other than that, the script works just fine and anyone reading this can feel free to use it themselves. Heres the full Script:
Function PFL-UserBackUp{
[cmdletbinding()]
Param(
[Parameter(Mandatory=$false,
ValueFromPipeLine=$true,
ValueFromPipeLineByPropertyName=$true)]
[Alias('CN','Computer','server','node')]
[ValidateLength(1, 15)]
[String[]]$ComputerName = $env:COMPUTERNAME )
Begin{
$Global:Shared_BackupPath = "\\server\share\"
}
Process{
Foreach($Computer in $ComputerName){
Try{
$PSSession = New-PSSession -ComputerName $Computer -ErrorAction Stop
[array]$User_List = Invoke-Command -ScriptBlock {
Get-ChildItem -Path "C:\Users" -Exclude Public, Default* |
Sort-Object -Property LastWriteTime -Descending } -Session $PSSession
$userinfo1 = foreach ($user in $User_List.name) {
$userinfo = (net user $user /domain | Select-String "Full Name" -ErrorAction SilentlyContinue) -replace "Full Name ", "" 2>&1 | Out-String -Stream
if ($userinfo.Length -lt 4) { "NO DISPLAY NAME in ADUC" }
elseif($LASTEXITCODE -eq 2) { "ACCOUNT NOT in ADUC" }
elseif($LASTEXITCODE -eq 0) { $userinfo }
else { "Error occured" }
}
$(for($i=0; $i -lt $User_List.Count; $i++){
[pscustomobject]#{
'User Display Name ' = "$($i): $($userinfo1[$i])"
' NAME ' = $User_List.name[$i]
'Last Modified' = "$($User_List.LastWriteTime[$i])"
'Profile Size ' = Try{
$ProfilePath = $User_List.FullName[$i]
$Profile_Sum = Invoke-Command -ScriptBlock {
Get-ChildItem -Path $Using:ProfilePath -Recurse |
Where-Object {$_.PSParentPath -match "Documents|Desktop|Music|Videos|Downloads|Links|Pictures|Favorites|Contacts" -and $_.DirectoryName -notmatch "OneDrive" } |
Measure-Object -Property length -Sum |
Select-Object -ExpandProperty Sum } -Session $PSSession
if($Profile_Sum -lt 1048576){ $TinyByte = " {0:N2}" -f ($Profile_Sum / 1KB) + " KB"; $TinyByte }
elseif($Profile_Sum -gt 1048576 -and $Profile_Sum -lt 1073741824){ $MediumByte = " {0:N2}" -f ($Profile_Sum / 1MB) + " MB"; $MediumByte }
elseif($Profile_Sum -gt 1073741824){ $GiganticByte = " {0:N2}" -f ($Profile_Sum / 1GB) + " GB"; $GiganticByte } #Profile Size
} Catch { "$($Error[0].Exception.Message.Split('.')[2].Trim())!" }
}
} ) | Out-Host
Write-Host "Press 'Q' to quit."
$ii = Read-Host -Prompt "Enter Number of Profile to Back-Up"
$i = $ii.Trim() -split ","
if([String]::IsNullOrEmpty($i) -eq $true) { "Null string"; Break }
elseif($i.ToLower() -like "q*") {"Q was selected. Stopping script."; Break }
<#
" "
" Following Profiles will be Saved:"
" ------------------------------------"
foreach($i in $index) { "$($i.trim()): $($userinfo1[$i])" }
" "
$Confirm = Read-Host -Prompt "Are you sure you want to continue? [Y/N]"
if($Confirm.ToLower().TrimStart() -like "n*" -or $Confirm.ToLower() -like "q*"){Break}
if([String]::IsNullOrEmpty($Confirm.Trim()) -eq $true) { "Null string"; Break }#>
$Profile_Path = "C:\Users\$($User_List.name[$i])"
$Literal_Name = $userinfo1[$i].Replace('/','-')
$Global:BackUp_Path = "$Global:Shared_BackupPath$Literal_Name"
$Test_Path = Test-Path -Path $Global:BackUp_Path
if($Test_Path -eq $false){
New-Item -Path $Global:BackUp_Path -ItemType Directory | Out-Null
Start-Process $Global:BackUp_Path}
elseif($Test_Path -eq $true){
$Find_OldName = Get-ChildItem -Path "$Global:Shared_BackupPath" -Filter "$Literal_Name" -Directory |
Sort-Object -Property LastWriteTime -Descending |
Select-Object -ExpandProperty BaseName -First 1
$New_PathName = $Find_OldName + "1"
New-Item -Path "$Global:Shared_BackupPath" -Name $New_PathName -ItemType Directory -OutVariable Global:BackUp_Path | Out-Null #Global:BackUp_Path variable declared
$Global:BackUp_Path = $Global:BackUp_Path.FullName
Start-Process $Global:BackUp_Path}
$Global:Start_Time = Get-Date -Format G
#Favorites Copy
$FireFox_Favorites = "C:\Users\$($User_List.name[$i])\AppData\Roaming\Mozilla\Firefox\Profiles\*.default\places.sqlite"
$Chrome_Favorites = "C:\Users\$($User_List.name[$i])\AppData\Local\Google\Chrome\User Data\Default\Bookmarks"
$Chrome_Favorites2 = "C:\Users\$($User_List.name[$i])\AppData\Local\Google\Chrome\User Data\Default\Bookmarks.bak"
$Sticky_Notes = "C:\Users\$($User_List.name[$i])\AppData\Local\Packages\Microsoft.MicrosoftStickyNotes_8wekyb3d8bbwe\LocalState\plum.sqlite"
$Favorites_Array = #($FireFox_Favorites,$Chrome_Favorites,$Chrome_Favorites2,$Sticky_Notes)
Foreach($File in $Favorites_Array){
$Test_File = Invoke-Command -ScriptBlock { Test-Path -Path $File }
if($Test_File -eq $true){
Copy-Item -Path $File -Destination $Global:BackUp_Path -Force -Recurse -FromSession $PSSession
}
}
#Folders Copy
$Folders = #('Desktop','Documents','Favorites','Links','Downloads','Music','Videos','Pictures','Contacts')
Foreach($Folder in $Folders){
#Create Arugments for seperate thread
$ArgumentsArray = $null
$ArgumentsArray = #()
$ArgumentsArray += "\\$Computer\c$\Users\$($User_List.name[$i])\$Folder"
$ArgumentsArray += $Global:BackUp_Path
$job = Start-Job -ScriptBlock { Copy-Item -Path $args[0] -Destination $args[1] -Force -Recurse } -Name $Folder -ArgumentList $ArgumentsArray
Register-ObjectEvent -InputObject $job -EventName StateChanged -Action {
#Start-Sleep -Milliseconds 500
$eventSubscriber | Unregister-Event
$eventSubscriber.Action | Remove-Job
if(-not (Get-EventSubscriber)){
$Profile_Sum = Get-ChildItem -Path $Global:BackUp_Path -Recurse |
Measure-Object -Property length -Sum |
Select-Object -ExpandProperty Sum
$Size = try{if($Profile_Sum -lt 1048576){ $TinyByte = " {0:N2}" -f ($Profile_Sum / 1KB) + " KB"; $TinyByte }
elseif($Profile_Sum -gt 1048576 -and $Profile_Sum -lt 1073741824){ $MediumByte = " {0:N2}" -f ($Profile_Sum / 1MB) + " MB"; $MediumByte }
elseif($Profile_Sum -gt 1073741824){ $GiganticByte = " {0:N2}" -f ($Profile_Sum / 1GB) + " GB"; $GiganticByte } } Catch {}
$Begin_Time = Get-Item -Path $Global:BackUp_Path | Select-Object -ExpandProperty LastWriteTime
$End_Time = Get-Date -Format G
Get-Job | Remove-Job
[System.Windows.MessageBox]::Show("Copying Complete!`nStart Time: $Begin_Time `nEnd Time: $End_Time `nProfile Size copied: $Size")
}
} | Out-Null
}
" "
Write-Output -InputObject "Copying will be done in background."
Write-Output -InputObject "You will be notified when copying is done."
} catch [System.Management.Automation.Remoting.PSRemotingTransportException]{
"Unable to connect to PC: $Computer `nError: $($Error[0].Exception.Message.Split('.')[2].Trim())!"
}
}
}
}
I removed some information that could get me in trouble but, it's all cosmetics.(:
EDIT: I must be on crack but, everything is working now. Only changes I made was clearing the global variables ($Global:var = $null) before assigning it a value. Thank you all for the suggestions. Another change i made was change Copy-Item to Robocopy instead.

To just answer your question:
Why is my if statement not being read properly?
Just before you evaluate Get-EventSubscriber your are cancelling your event subscription and thus deleting your event subscriber. Get-EventSubscriber therefore returns $null which evaluates to $true, when negated. In conclusion, the code after your if statement will always be executed immediately.
Commented code:
Register-ObjectEvent -InputObject $job -EventName StateChanged -Action {
$eventSubscriber | Unregister-Event # Here you cancel your event subscription
$eventSubscriber.Action | Remove-Job
if (-not (Get-EventSubscriber)) { # Therefore, Get-EventSubscriber returns $null; not $null evaluates to $true
...
The relevant part in the documentation of Unregister-Event:
The Unregister-Event cmdlet cancels an event subscription that was created by using the Register-EngineEvent, Register-ObjectEvent, or Register-WmiEvent cmdlet.
When an event subscription is canceled, the event subscriber is deleted from the session and the subscribed events are no longer added to the event queue. When you cancel a subscription to an event created by using the New-Event cmdlet, the new event is also deleted from the session.

Related

how to use variable out of invoke-command in powershell?

I have below Invoke-command code, the script using hponcfg.exe file on remote server to get ILO configuration. few servers having issue with power capping and error returned by hponcfg.exe as
"Message = 0x0089 Power capping information is not available at this time, try again later."
My question is: I want to capture this error if generated by hponcfg inside invoke-command scriptblock and use it out of scriptblock.
$CurrentDir = (Split-Path $invocation.MyCommand.Path).ToLower()
$CurrentDir
$Credential = get-credential -message "Please supply SA account details."
$servers = gc .\servers.txt
#$Global:ScriptDir = Split-Path $script:MyInvocation.MyCommand.Path
$date = (get-date).ToString("yyyyMMdd_HHmm")
$ILOContent = ".\ILOConfigData_$date.csv"
New-Item -path $ILOContent -type file -Force | out-null
Add-Content -Path $ILOContent -Value "ILO_Name,Model,ILOFIrmware,ILODevice,ILOFWDate,ILO_Domain,Network_Details,ILO_TimeZone,Directory_Users,LDAP_Directory_Authentication,Directory_Groups,SNMP_Settings,Directory_Server_Address"
Foreach($server in $servers){
if (Test-Connection -ComputerName $server -Quiet)
{
#$Frompath = ".\ILO_Prerequisite\"
#$To_Path = "C:\Program Files\Hewlett Packard Enterprise\HPONCFG"
$tmp="Drv_$server"
new-psdrive $tmp filesystem "\\$server\C$" -cred $cred|Out-Null
$Model = (Get-WmiObject -ComputerName $server -Class:Win32_ComputerSystem).model
Write-Host "Validating HPE pre-requisites on server:"$server -BackgroundColor DarkGray -ForegroundColor White
if (-not(test-path("$($tmp):\Program Files\Hewlett Packard Enterprise\HPONCFG")))
{
Write-Host "Corrupt 'HPONCFG' folder structure found. Remediating, will take few seconds." -ForegroundColor Red
New-Item -Path ("$($tmp):\Program Files\Hewlett Packard Enterprise\") -ItemType Directory -Name HPONCFG -Force|Out-Null
$To_Path =("$($tmp):\Program Files\Hewlett Packard Enterprise\HPONCFG")
$From_Path = ".\ILO-PreRequisite\*"
copy-item -path $From_Path -Destination $To_Path -recurse -Force
Sleep(6)
Write-Host "'HPONCFG' folder structure remediated." -ForegroundColor Green
}
Elseif (-not(test-path("$($tmp):\Program Files\Hewlett Packard Enterprise\HPONCFG\hponcfg.exe")))
{
$To_Path =("$($tmp):\Program Files\Hewlett Packard Enterprise\HPONCFG")
Write-Host "Corrupt 'HPONCFG' folder structure found. Remediating, will take few seconds." -ForegroundColor Red
copy-item -path $From_Path -Destination $To_Path -recurse -Force
Sleep(6)
Write-Host "'HPONCFG' folder structure remediated" -ForegroundColor Green
}
remove-psdrive -name $tmp -force
#if (-not(test-path "C:\Program Files\Hewlett Packard Enterprise\HPONCFG\hponcfg.exe"))
# {
# do copy job
# write-host "Copying files and folders from $frompath to $topath" -ForegroundColor Yellow
# copy-item -path $frompath -Destination $topath -recurse
# }
$export = Invoke-Command -ComputerName $server -Credential $Credential -ScriptBlock {
New-Item -Path "C:\Program Files\Hewlett Packard Enterprise\HPONCFG" -ItemType File -Name Current_ILOConfig.xml -Force| Out-Null
Set-Location "C:\Program Files\Hewlett Packard Enterprise\HPONCFG"
$ILODataPath = Get-Location
$WantFile = "$ILODataPath\Current_ILOConfig.txt"
$FileExists = Test-Path $WantFile
If ($FileExists -eq $True) {Remove-Item $WantFile }
Sleep(2)
Write-Host "Gathering current ILO configuration for $ENV:COMPUTERNAME" -ForegroundColor Yellow
& "C:\Program Files\Hewlett Packard Enterprise\HPONCFG\hponcfg.exe" /a /w `
"C:\Program Files\Hewlett Packard Enterprise\HPONCFG\Current_ILOConfig.xml" |Out-Null
Get-Content .\Current_ILOConfig.xml
}
$export|Out-File "Current_ILOConfig.txt"
Sleep(3)
$ILORAW_DATA = Get-Content .\Current_ILOConfig.txt
$ILORAW_DATA|ForEach-Object{
$_ -replace '<!-- ' `
-replace ' -->' `
-replace '<' `
-replace ' />' `
-replace '"' `
}|Set-Content .\Current_ILOConfig.txt
$ILO_DATA = Get-Content .\Current_ILOConfig.txt
Write-Host "Getting ILO DNS details"
$DNS_NAME = $ILO_DATA |Where {$_ |Select-String -Pattern " DNS_NAME VALUE"," DOMAIN_NAME VALUE"}
$ILONAME = $DNS_NAME -split "="
$ILO_Name = $ILONAME[1]
$ILO_Domain = $ILONAME[3]
Write-Host "Getting ILO Network details"
$NT = $ILO_DATA | where {$_ |Select-String -Pattern " IP_ADDRESS VALUE"," SUBNET_MASK"," GATEWAY_IP_ADDRESS"," PRIM_DNS_SERVER VALUE", " SEC_DNS_SERVER VALUE"," TER_DNS_SERVER VALUE" }
$Network = [array]$NT -join "`n"
$Network_Details = $Network.Trim()
Write-Host "Getting ILO TimeZone"
$TZ= $ILO_DATA |Where {$_ | Select-String -Pattern " TIMEZONE VALUE"}
$TimeZone =$TZ -Split "="
$ILO_TimeZone = $TimeZone[1]
Write-Host "Getting ILO Directory Server Address" # Directory_Server_Address
$DSA = $ILO_DATA |Where {$_ | Select-String -Pattern " DIR_SERVER_ADDRESS"}
$DIR_SERVERADDRESS = $DSA -Split "="
$Directory_Server_Address = $DIR_SERVERADDRESS[1]
$ILODeviceID = #()
$ILODev = $ILO_DATA|where{$_|Select-String -Pattern "Device: "}
$ILODevStr = $ILODev -split(' ')
$ILODeviceID += $ILODevStr[1..2] -as [string]
$ILODeviceID += $ILODevStr[7]
$ILODeviceID += $ILODevStr[-1]
Write-Host "Getting LDAP Directory Authentication Enabled/Disabled?"
$LDAP_DIR = $ILO_DATA |Where {$_ | Select-String -Pattern " DIR_AUTHENTICATION_ENABLED"}
$LDAP_DIR_STATUS = $LDAP_DIR -split "="
$LDAP_Directory_Authentication = $LDAP_DIR_STATUS[1]
Write-Host "Getting ILO Device detail"
$ILOFIrmware = $ILODevStr[7]
Write-Host "Getting ILO Firmware Version"
$ILODevice = $ILODevStr[1,2]
Write-Host "Getting ILO Firmware Version date"
$ILOFWDate = $ILODevStr[-1]
Write-Host "Getting SNMP Settings" #SNMP_Settings
$SNMPADDRESS = $ILO_DATA |Where {$_ | Select-String -Pattern "SNMP_ADDRESS"}
$SNMP_DATA = #()
foreach($SNMP in $SNMPADDRESS)
{
$SNMP_DATA +=($SNMP -split "VALUE=")[1]
}
$SNMP_Settings = $SNMP_DATA -join "`n"
Write-Host "Getting ILO Directory User details"
$DIR_USER = $ILO_DATA |Where {$_ | Select-String -Pattern " DIR_USER_CONTEXT"}
$User =#()
foreach($Usr in $DIR_USER)
{
$User += ($Usr -split "VALUE=")[1]
}
#$User
$Directory_Users = $User -join "`n"
#group Account details
Write-Host "Getting ILO Directory Group details"
$DIR_GRPACCT = $ILO_DATA |Where {$_ | Select-String -pattern " DIR_GRPACCT"}
$ACCTs = #()
for($a=1;$a -le 10;$a++)
{
$GroupName = "DIR_GRPACCT" + $a + "_NAME"
#$Privilege = "DIR_GRPACCT" + $a + "_PRIV"
$DIR_GRPACCT = $ILO_DATA |Where {$_ | Select-String -pattern $groupname}
foreach ($acct in $DIR_GRPACCT)
{
$ACCTS += ($acct -split "VALUE=")[1]
}
$DIR_GRPACCTS = ($ACCTS -join "`n")
}
$data = "`"$ILO_Name`",`"$Model`",`"$ILOFIrmware`",`"$ILODevice`",`"$ILOFWDate`",`"$ILO_Domain`",`"$Network_Details`",`"$ILO_TimeZone`",`"$($Directory_Users.trimend())`",`"$LDAP_Directory_Authentication`",`"$($DIR_GRPACCTS.trimend())`",`"$($SNMP_Settings.trimend())`",`"$($Directory_Server_Address.trimend())`""
$Data |Out-File -Append $ILOContent
}
else
{
write-host -ForegroundColor Red "Server $server is not reachable"
$data = "`"$server`",`"not reachable`""
$Data |Out-File -Append $ILOContent
}
}
#Clear User defined variables
Write-Host "Performing Clean-up" -ForegroundColor Yellow
#Clear-Variable -Name ILO*
Function Get-ScriptVariable ($Name = '*')
{
# these variables may exist in certain environments (like ISE, or after use of foreach)
$special = 'ps','psise','psunsupportedconsoleapplications', 'foreach', 'profile'
$ps = [PowerShell]::Create()
$null = $ps.AddScript('$null=$host;Get-Variable')
$reserved = $ps.Invoke() |
Select-Object -ExpandProperty Name
$ps.Runspace.Close()
$ps.Dispose()
Get-Variable -Scope Global |
Where-Object Name -like $Name |
Where-Object { $reserved -notcontains $_.Name } |
Where-Object { $special -notcontains $_.Name } |
Where-Object Name
}Get-ScriptVariable|Out-Null
Get-ScriptVariable |Clear-Variable ;Write-Host "Clean-up completed." -ForegroundColor Green
Write-Host "Check detailed log stored at path: "$CurrentDir -ForegroundColor Green```
You can use try-catch-finally method to get your error messages.
Hi I have modified your script invoke-command part only. Please test and use it. This script is not tested.
$export = Invoke-Command -ComputerName $server -Credential $Credential -ScriptBlock {
try {
New-Item -Path "C:\Program Files\Hewlett Packard Enterprise\HPONCFG" -ItemType File -Name Current_ILOConfig.xml -Force | Out-Null
Set-Location "C:\Program Files\Hewlett Packard Enterprise\HPONCFG"
$ILODataPath = Get-Location
$WantFile = "$ILODataPath\Current_ILOConfig.txt"
$FileExists = Test-Path $WantFile
If ($FileExists -eq $True) { Remove-Item $WantFile }
Sleep(2)
Write-Host "Gathering current ILO configuration for $ENV:COMPUTERNAME" -ForegroundColor Yellow
& "C:\Program Files\Hewlett Packard Enterprise\HPONCFG\hponcfg.exe" /a /w `
"C:\Program Files\Hewlett Packard Enterprise\HPONCFG\Current_ILOConfig.xml" | Out-Null
Get-Content .\Current_ILOConfig.xml
}
catch {
return $_
}
}
$export | Out-File "Current_ILOConfig.txt"

Powershell remote installed softwares using workflow paralell

I am trying to convert my inventory script to be able to get a csv list of installed softwares on remote servers using workflows but I am not able to get it.
$tod = Get-Date;
$local = $PSScriptRoot +"\_Output\"+ "$((Get-Date).ToString('yyyyMMdd'))" + "\InstalledSoftwares\";
if(!(Test-Path -Path $local ))
{
New-Item -ItemType Directory -Path $local
}
$ItemList = Import-Csv $($PSScriptRoot + "\_HostList.CFG") -Header Srv -Delimiter ";"
Write-Host $ItemList.srv
workflow AllInstalledSoft {
ForEach -Parallel ($Serv in $ItemList.srv) {
#$Serv = $_.Srv
if (Test-Connection -computer $Serv -count(1) -quiet)
{
InlineScript { Write-Host $using:Serv "Is Reachable" -ForegroundColor Green
$file = $using:Serv+"_InstalledSoft"+"-{0:yyyyMMdd}.csv" -f $tod
$ExportFile = $local+$file
Get-WmiObject -Class Win32_Product -PSComputerName $using:Serv | select-object #{l="HostName";e={$using:Serv}},Name,InstallDate,InstallLocation,Vendor,Version,Caption,LocalPackage,IdentifyingNumber | Export-CSV -path $ExportFile -notypeinformation}
}
else
{
InlineScript { Write-Host $using:Serv "Is UnReachable" -ForegroundColor Red}
}
}
}
AllInstalledSoft
I cannot test but try this and see if it works. Don't try with the full hostname list, just reduce it to 5 computers to test if it works.
EDIT 3 :
$tod = (Get-Date).ToString('yyyyMMdd')
$local = $PSScriptRoot + "\_Output\" + $tod + "\InstalledSoftwares"
if(!(Test-Path -Path $local )){
New-Item -ItemType Directory -Path $local
}
$ItemList = Import-Csv $($PSScriptRoot + "\_HostList.CFG") -Header Srv -Delimiter ";" | Select-Object -Skip 1
workflow AllInstalledSoft {
param (
[parameter(Mandatory=$true)][array]$ItemList,
[parameter(Mandatory=$true)][string]$LocalExport,
[parameter(Mandatory=$true)][string]$Tod
)
ForEach -Parallel ($Serv in $ItemList) {
if(Test-Connection -ComputerName $Serv -Count 1 -Quiet){
$file = "$($Serv)_InstalledSoft-$Tod.csv"
$ExportFile = "$LocalExport\$file"
try {
Get-WmiObject -Class Win32_Product -PSComputerName $Serv -ErrorAction Stop | Select-Object PSComputerName,Name,InstallDate,InstallLocation,Vendor,Version,Caption,LocalPackage,IdentifyingNumber | Export-CSV -Path $ExportFile -NoTypeInformation
}
catch {}
}
}
}
AllInstalledSoft -LocalExport $local -ItemList $ItemList.Srv -Tod $tod

How to update variables in script?

Script should restart service and save current data and time in file after memory usage reach the limit. But it doesn't save current time and in second if when service is stopped it doesn't do else. It always show the same values in $data and $stat. I am not sure where I made mistake.
$proc = 'process name'
$serv = 'service name*'
$ram = 10MB
$inter = 1
$data = Get-Date -format "yyyy/MM/dd HH:mm:ss"
$log = "c:\log.txt"
$stat = Get-Process $proc -EA SilentlyContinue
while ($true) {
if ((Get-Process $proc -EA SilentlyContinue | Select-Object -Exp ws) -gt $ram) {
Restart-Service $serv
Add-Content -path $log -value ($data + "`t" + "Restarting")
Start-Sleep -m 10000
if ($stat -ne $null) {
Add-Content -path $log -value "Working"
} else {
Start-Service $serv
Add-Content -path $log -value ($data + "`t" + "Starting")
}
}
Start-Sleep -s $inter
}
The statements in your variable assignments are evaluated at the time of assignment, not when the variable is used. To get the latter you could define the statements as scriptblocks:
$data = { Get-Date -format 'yyyy\/MM\/dd HH:mm:ss' }
$stat = { Get-Process mysqld -ea SilentlyContinue }
Use the call operator (&) in an expression (()) or subexpression ($()) to evaluate the scriptblocks at a later point in your script:
if ((&$stat) -ne $null) {
Add-Content -Path $log -Value "Working"
} else {
Start-Service $serv
Add-Content -Path $log -Value "$(&$data)`tStarting"
}
Probably a more convenient way is to define the operations as functions:
function Get-Timestamp { Get-Date -format 'yyyy\/MM\/dd HH:mm:ss' }
function Test-MySQLProcess { [bool](Get-Process mysqld -EA SilentlyContinue) }
and use them like this:
if (Test-MySQLProcess) {
Add-Content -Path $log -Value "Working"
} else {
Start-Service $serv
Add-Content -Path $log -Value "$(Get-Timestamp)`tStarting"
}
As a side note, you should escape forward slashes in date format strings, otherwise Windows substitutes them with whatever date separator character is configured in your system's regional settings.

Powershell activating script on remote machine - remote machine cannot see network shares

I have a database server not in a domain, that the task scheduler is corrupt and I don't have the time or resources to repair it yet so I created a script that runs from another non-domain server using task scheduler that activates a second script located on the database server to copy files. On the database server the script when activated manually sees everything and does its job but when I try remotely activating the script it runs and sees everything but the network drives (W:). I am using credssp in the script which connects fine see below - Question how can I get the script to see the network share on the remote server
-------------Script A---------------------------------------------
$username = "Administrator"
$computerA = "<addressA>"
$computerB = "<addressB>"
$PwdLocation = "c:\test\password.txt"
#enable-wsmancredssp -role client -delegatecomputer $computerB
$password = Get-Content $PwdLocation | ConvertTo-SecureString
$credential = new-object -typename System.Management.Automation.PSCredential - argumentlist $username,$password
Invoke-Command -ComputerName $computerB -ScriptBlock {\\<remote server>\test\delete.ps1} -ArgumentList $ComputerA -Credential $credential
exit
----------------------Remote Script B ---------------------------------------
Function mailer {
$recipients = "<names>"
$smtp = "smtp.org"
$emailTo = $recipients
$emailFrom = "no-reply#org.org"
$smtpserver="smtp.org"
$smtp=New-Object Net.Mail.SmtpClient($smtpServer)
$smtp.Send($emailFrom, $emailTo, $subject, $message)
}
Function StopEverything {
$subject = "Stopped Script Delete.PS1 becuase of no connection"
$message = ""
for($i=0;$i -le $tot-1;$i++)
{
$path = $bfs[$i]
if (Exists-Dir($path))
{
$message += [string]::concat($path, " Connected`n")
}
else
{
$message += [string]::concat($path, " Cannot Connect`n")
}
}
mailer
Exit
}
Function Exists-Dir($path) {
if ([IO.Directory]::Exists($path))
{
return $true;
}
else
{
return $false;
}
}
$ScriptStart = (Get-Date)
[array]$bfs = "F:\Backups\NetPerfMon","F:\Backups\NetPerfMon_Aux","W:\Backups\NetPerfMon_Aux","W:\Backups\NetPerfMon"
$tot = $bfs.count
for($i=0;$i -le $tot-1;$i++)
{
$path = $bfs[$i]
if (Exists-Dir($path))
{
$message += [string]::concat($path, " Connected`n")
$subject = "Start Script Delete.PS1 on " + $ScriptStart
}
else
{
$message += [string]::concat($path, " Cannot Connect`n")
StopEverything
}
}
$message += " "
$message +=
mailer
$limit = (Get-Date).AddDays(-7)
$limit1 = (Get-Date).AddDays(-14)
$limit2 = (Get-Date).AddDays(-1)
$FB = "F:\Backups\NetPerfMon"
$FBAux = "F:\Backups\NetPerfMon_Aux"
$WBAux = "W:\Backups\NetPerfMon_Aux"
$WBBak = "W:\Backups\NetPerfMon"
Get-ChildItem -Path $FB | Where-Object { !$_.PSIsContainer -and $_.LastWriteTime - lt $limit } | Remove-Item -Force | OUT-NULL #Remove items greater than 7 days
Get-ChildItem -Path $FBAux | Where-Object { !$_.PSIsContainer -and $_.LastWriteTime -lt $limit } | Remove-Item -Force | OUT-NULL #Remove items greater than 7 days
Get-ChildItem -Path $WBBak | Where-Object { !$_.PSIsContainer -and $_.LastWriteTime -lt $limit1} | Remove-Item -Force | OUT-NULL #Remove items greater than 14 days
Get-ChildItem -Path $FB | where {$_.extension -eq ".bak"} | Where-Object { !$_.PSIsContainer -and $_.LastWriteTime -gt $limit2} | Copy-Item -destination $WBBak | OUT- NULL #Copy items within 1 day that have extension .bak
Get-ChildItem -Path $FBAux | where {$_.extension -eq ".bak"} | Where-Object { !$_.PSIsContainer -and $_.LastWriteTime -gt $limit2} | Copy-Item -destination $WBAux | OUT- NULL #Copy items within 1 day that have extension .bak
$ScriptEnd = (Get-Date)
$RunTime = New-Timespan -Start $ScriptStart -End $ScriptEnd
"Elapsed Time: {0}:{1}:{2}" -f $RunTime.Hours,$Runtime.Minutes,$RunTime.Seconds
$subject = "Stop Script Delete.PS1 on " + $ScriptEnd
$message = ""
$message += " "
$message += "Time to completion: {0}:{1}:{2}" -f $RunTime.Hours,$Runtime.Minutes,$RunTime.Seconds
mailer
Use the complete UNC paths not drive letters OR do a "net use X: \my\unc\share" at the top of your script mapping the drives right in the script.
edit: if you do this you will have to explicitly specify the password in the net use command: net use x: \\my\share /user:mydom\myuser mypassword

Speed up Test-Connection before Foreach

I made a script to check if users desktop folder are under the cuota limitation, if they're under the cuota limitation the backup to the server will be done correctly.
each user have his computer, so source CSV looks like:
pc1,user1
pc2,user2
pc800,user800
Some computers are Windows Xp and some W7, and the paths can be different 'cause of that I'm using Test-Path
W7 = C:\users\$user\desktop
XP = C:\document and settings\$user\desktop
But Test-Path is SUPER SLOW and I started to use a Test-Connection -count 1 before each Test-path
Anyway, the script still SLOW, in each "bad ping test" I lose lot of time.
CODE:
$csvLocation = '~\desktop\soourceReport.csv'
$csv = import-csv $csvLocation -Header PCName, User
$OuputReport = '~\desktop\newReport.csv'
# info:
# "209715200" Bytes = 200 MB
$cuota = "209715200"
$cuotaTranslate = "$($cuota / 1MB) MB"
Write-Host "Cuota is set to $cuotaTranslate"
$count=1
foreach($item in $csv)
{
write-host "$count# Revisando" $item.User "en" $item.PCName "..." #For debug
if (Test-Connection -Quiet -count 1 -computer $($item.PCname)){
$w7path = "\\$($item.PCname)\c$\users\$($item.User)\desktop"
#echo $w7path #debug
$xpPath = "\\$($item.PCname)\c$\Documents and Settings\$($item.User)\Escritorio"
#echo $xp #debug
if(Test-Path $W7path){
$desktopSize = (Get-ChildItem -Recurse -force $w7path | Measure-Object -ErrorAction "SilentlyContinue" -property length -sum)
write-host -ForegroundColor Green "access succeed"
if($($desktopSize.sum) -gt $cuota){
$newLine = "{0},{1},{2}" -f $($item.PCname),$($item.User),"$("{0:N0}" -f $($desktopSize.sum / 1MB)) MB"
$newLine | add-content $outputReport
Write-Host -ForegroundColor Yellow "cuota exceeded! -- added"
}
else{
Write-Host -ForegroundColor DarkYellow "cuota OK"
}
}
elseif(Test-Path $xpPath){
$desktopSize = (Get-ChildItem -Recurse -force $xpPath | Measure-Object -ErrorAction "SilentlyContinue" -property length -sum)
write-host -ForegroundColor Green "access succeed"
if($($desktopSize.sum) -gt $cuota){
$newLine = "{0},{1},{2}" -f $($item.PCname),$($item.User),"$("{0:N0}" -f $($desktopSize.sum / 1MB)) MB"
$newLine | add-content $outputReport
Write-Host -ForegroundColor Yellow "cuota exceeded! -- added"
}
else{
Write-Host -ForegroundColor DarkYellow "cuota OK"
}
else{
write-host -ForegroundColor Red "Error! - bad path"
}
}
else{
write-host -ForegroundColor Red "Error! - no ping"
}
$count++
}
Write-Host -ForegroundColor green -BackgroundColor DarkGray "All done! new report stored in $report"
To improve it I stored all computers in a $list using another Foreach, before the firstly mentioned SLOW-Foreach loop.
foreach($pcs in $csv){
$alivelist += #( $pcs.PCName )
}
Test-Connection -quiet -count 2 -computer $alivelist
Now, I don't now how to UPDATE or remove the rows ("dead" pc,user) from the SOURCE CSV before to enter into the second Foreach.
I need some of your "magic", or at least some ideas!
thanks
To speed up your script you need to run the checks in parallel (as others have already mentioned). Put your checks and the worker code in a scriptblock:
$sb = {
Param($computer, $username)
if (Test-Connection -Quiet -Count 2 $computer) { return }
$w7path = "\\$computer\c$\users\$username\desktop"
$xpPath = "\\$computer\c$\Documents and Settings\$username.TUITRA..."
if (Test-Path $W7path) {
#...
} elseif (Test-Path $xpPath) {
#...
} else {
#...
}
}
Then run the scriptblock as parallel jobs:
$csv | ForEach-Object {
Start-Job -ScriptBlock $sb -ArgumentList $_.PCName, $_.User
}
# wait for completion
do {
Start-Sleep -Milliseconds 100
} while (Get-Job -State 'Running')
# cleanup
Get-Job | ForEach-Object {
Receive-Job -Id $_.Id
Remove-Job -Id $_.Id
} | Out-File $outputReport
Use a queue if you need to limit the number of parallel jobs.
test-connection is weirdly fast with the -asjob parameter, pinging about 200 computers in 4 seconds:
$list = cat hp.txt
test-connection $list -AsJob ; job | receive-job -wait -AutoRemoveJob