Powershell DISM Progression bar - powershell

I have a problem, I am building a powershell script to restore / save wim images using the DISM command.
So I use a winform interface, with a progress bar.
However, I can't find a way to send the% information for my progress bar.
Currently I have done tests with my DISM command in fact for example >> c: \ test and I manage to recover the% but I cannot do them simultaneously.
Here is the code, do you have any idea?
Foreach ( $line in "c:\test.txt" )
{
$content = Get-Content -Path 'c:\test.txt'
$content
$count = ($content | Select-String -Pattern '%' -AllMatches)
$PCcomplete = $count.Count-1
}
Dism /Capture-Image /ImageFile:$chemin /CaptureDir:$choixlettre\ /Name:$nom /Compress:max /LogLevel:4 >> c:\test.txt

Finally, it's work ! But my progression bar stop at 96...97 the count forget some number..
$sb = [scriptblock]::Create("dism /apply-image /imagefile:$chemin /index:1 /applydir:t: /LogLevel:4 >>t:\test.txt")
$job = Start-Job -ScriptBlock $sb
#
$pccomplete = 0
$pccomplete1 = 0
# Boucle
while((Get-Job | Where-Object {$_.State -ne "Completed"}).Count -gt 0)
{
$content = get-content -Path 't:\test.txt'
$count = ($content | Select-String -Pattern '%' -AllMatches)
$PCcomplete = $count.Count
start-sleep -Second 2
if( $pccomplete1 -ne $pccomplete )
{
$pccomplete1 = $pccomplete
$richtextBox_history.AppendText("$PCcomplete`n")
$progressBar1.Value = $pccomplete
}

Related

workflow parallel is executed in the same time as without parallel

I've tried searching in text in parallel and no. Runtime is the same
To determine the execution time, I used a Measure-Command -Expression
$listlogtoday = Get-ChildItem -Path $folder\*.log | Where-Object Length -ne 0
$arraylist = $listlogtoday.Name
$tmp="code "
workflow Test-ParallelForeach
{
param(
[array[]]$arraylist
)
foreach -parallel ($namefile in $arraylist )
{
$text = ((Select-String -Path "C:\test_ps1\$namefile" -Pattern "text_text") -replace "(?s)^.*$tmp", '') -replace "text2_text2.",""
$allkey += $text
}
}
Test-ParallelForeach -arraylist $arraylist
$allkey = $allkey | select -Unique
write-host ($allkey -join "`n")

Loop in powershell

Hello Guys need some help, tips with script:
$path = ".\" # path do txt
$server = "server" # server.txt
$paczki = ".\paczki\"
$missingi = "$path\$server.txt"
$plik = get-content $missingi
foreach ($j in $plik) {
Write-Output "1"
$wynik = Get-ChildItem "$paczki" | ? {$_.name -match "$j"}
if ($wynik -eq $null) {
# Write-Host $i
}
else {
Write-Output "2"
Write-Host $wynik "znaleziono"
Copy-Item $paczki\$wynik -Destination \\$server\c$\temp\ -force
}
}
#### BAT GENERATOR #####
Write-Output "3"
# & .\bat_generator.ps1
$zapis = "$path\test.bat"
"pushd %~dp0" > $zapis
$nazwa = Get-ChildItem "\\$server\c$\temp\" | select name
foreach ($i in $nazwa) {
$text = $i.name + " /norestart /quiet"
$text >> $zapis
}
"ppd0" >> $zapis # dodaj ppd0
move-item -path .\test.bat -destination \\$server\c$\temp\ -Force # skopiuj .bat na server
At first I create file with name of server, for example server.txt in this server we have list of KBs. Scripts searching in folder paczki that KB exist if yes copying this in server and create .bat
I would like do add automatically searching all .txt files eg server.txt, & server1.txt and use it in loop, I thought about something like that:
$pliki_txt= Get-ChildItem $path -Filter "*.txt" | % {$_.BaseName}
and put it in loop but its not really working, I try to add loop in this place:
for ($i in pliki_txt)
$path = ".\" # path do txt
$server="server" # server.txt
$pliki_txt= Get-ChildItem $path -Filter "*.txt" | % {$_.BaseName}
(....)
What am I doing wrong? Is there any easier way? Script is only working when I put manually set $server like $server="serwer"
You can try this:
$path = ".\"
Get-ChildItem $path -Filter *.txt | %{
$content = Get-content $_.FullName
Foreach($server in $content){
write-host $server
}
}
If I got that right, the issue here is that you're not putting the lines in the right order.
From your original code I would change the following
$path = ".\" # path do txt
$server = "server" # server.txt
$paczki = ".\paczki\"
# $missingi = "$path\$server.txt"
$missingi = Get-ChildItem -Path $path -Filter server*.txt | Select -ExpandProperty Name
foreach ($m in $missingi) {
$plik = get-content $m
( ... )
}
That way you'll check every server*.txt file in that path and process it accordingly.
Or you could even turn it into a parameterized script like this
Param(
[Parameter(Mandatory = $true)]
[String]$path,
[Parameter(Mandatory = $true)]
[String]$pattern,
[Parameter(Mandatory = $true)]
[String]$packzi
)
$missingi = Get-ChildItem -Path $path -Filter *.txt | Select -ExpandProperty | Select-String "$pattern"
foreach ($m in $missingi) {
$plik = get-content $m
foreach ($j in $plik) {
Write-Output "1"
$wynik = Get-ChildItem "$paczki" | ? {$_.name -match "$j"}
if ($wynik -eq $null) {
# Write-Host $i
}
else {
Write-Output "2"
Write-Host $wynik "znaleziono"
Copy-Item $paczki\$wynik -Destination \\$server\c$\temp\ -force
}
}
#### BAT GENERATOR #####
Write-Output "3"
# & .\bat_generator.ps1
$zapis = "$path\test.bat"
"pushd %~dp0" > $zapis
$nazwa = Get-ChildItem "\\$server\c$\temp\" | select name
foreach ($i in $nazwa) {
$text = $i.name + " /norestart /quiet"
$text >> $zapis
}
"ppd0" >> $zapis # dodaj ppd0
move-item -path .\test.bat -destination \\$server\c$\temp\ -Force # skopiuj .bat na server
}
Then you would run it like this:
.\YourScript.ps1 -path ".\" -pattern "server" -packzi ".\packzi\"
That will give you more flexibility if you want to change the source path, the name pattern or the search patch.
I hope this helps.

Powershell script - Start-Job & MSIEXEC

I wonder if you can help please? I have the need to write a Powershell script to execute an MSI script.
I also need to set a time out on the process (as the MSIs we're given sometimes hang).
I've seen that you can acheive this by using the Start-Job/ Wait-Job process
Obviously the code below in in a severe state of butchery currently
Thanks in advance
$timeoutSeconds = 20
$uninstall32 = gci "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" | foreach { gp $_.PSPath } | ? { $_ -match "My File" } | select UninstallString$uninstall64 = gci "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" | foreach { gp $_.PSPath } | ? { $_ -match "Vix.Cbe.SalesTransaction" } | select UninstallString
Echo "uninstall32 :" $uninstall32
if ($uninstall32) {
$uninstall32 = $uninstall32.UninstallString -Replace "msiexec.exe","" -Replace "/I","" -Replace "/X",""
$uninstall32 = $uninstall32.Trim()
$32p = #("/X", "$uninstall32", "/b")
}
Echo "uninstall32 :" $uninstall32
Echo "u32 :" $32p
$32j = Start-Job msiexec -ArgumentList $32p
if (Wait-Job $32j -Timeout $timeoutSeconds) { Receive-Process $32j }
Remove-Process -force $32j
You don't have to mess with jobs to do that. Here is the easy way:
start Notepad -PassThru | select -ExpandProperty id | set id
sleep 60
kill $id -ea 0
This might not work if app spawns another app and exits as the Id will be wrong. In that case you will probably have to hunt it in the process list or via cmd line params.
Thanks to majkinetor I managed to alter the code sufficiently to acheive my goal.
The only thing is that obviously whether the process is still actively uninstalling or not, its killed after the TOSecs value.
This should be good enough for what I need.
So to explain for anyone else looking for a similar solution:
This process checks both 32 bit and 64 bit Registry entries for an MSI similar to the ServiceName (Urbancode Deploy parameter is the '${p:ServiceName}' passed to the script at runtime)
If it finds an entry it'll execute the uninstall code for the specific 32/64 MSI
/x = Uninstall
$uninstall64/32 = GUID of the Uninstall part to the MSI
/nq = quiet uninstall with no GUI (infact in isolation testing you get a Yes/No dialogue)
The uninstall will run for the amount of seconds that you set in $TOSecs
Hope this helps someone else
$TOSecs = 30
$uninstall32 = gci "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" | foreach { gp $_.PSPath } | ? { $_ -match "'${p:ServiceName}'" } | select UninstallString
$uninstall64 = gci "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" | foreach { gp $_.PSPath } | ? { $_ -match "'${p:ServiceName}'" } | select UninstallString
if ($uninstall64) {
$uninstall64 = $uninstall64.UninstallString -Replace "msiexec.exe","" -Replace "/I","" -Replace "/X",""
$uninstall64 = $uninstall64.Trim()
Write "Uninstalling 64bit " '${p:ServiceName}'
start-process "msiexec.exe" -arg "/X $uninstall64 /nq" -PassThru |
select -ExpandProperty id | set id
#Echo "proc id = "$id
sleep $TOSecs
kill $id -ea 0
}
if ($uninstall32) {
$uninstall32 = $uninstall32.UninstallString -Replace "msiexec.exe","" -Replace "/I","" -Replace "/X",""
$uninstall32 = $uninstall32.Trim()
Write "Uninstalling 32bit " '${p:ServiceName}'
start-process "msiexec.exe" -arg "/X $uninstall32 /nq" -PassThru |
select -ExpandProperty id | set id
#Echo "proc id = "$id
sleep $TOSecs
kill $id -ea 0
}

Convert powershell script saving outlook attachments to save them from not inbox but inbox subfolder

I have a script i scraped from other scripts. It works except i am quite new to powershell and am a sys admin not a dev, (but reading my ass off). I can get the scrtipt to work downloading attachments from inbox in outlook but need it to download attachments from a subfolder instead:
############################# Outlook Call ##############################
$olFolderInbox = 6
$outlook = new-object -com outlook.application;
$ns = $outlook.GetNameSpace("MAPI");
$inbox = $ns.GetDefaultFolder($olFolderInbox)
$messages = $inbox.items
write-host $messages.count
$messcount = $messages.count
foreach($message in $messages){
##############Save Attachments################
$filepath = "c:\attachments\"
$message.attachments|foreach {
Write-Host $_.filename
$attr = $_.filename
$_.saveasfile((Join-Path $filepath $_.filename))
$a = $_.filename
If ($a.Contains("")) {
$_.saveasfile((Join-Path $filepath $a))
}
}
}
###########END##########
Any Ideas anyone? Would be massively grateful.
$OutputFolder = 'C:\tests';
$ErrorActionPreference= 'silentlycontinue'
$outlook = New-Object -ComObject Outlook.Application;
$olFolderInbox = 6;
$ns = $outlook.GetNameSpace("MAPI");
$inbox = $ns.GetDefaultFolder($olFolderInbox);
$inbox.Folders `
| ? Name -eq 'colour' `
| % Items `
| % Attachments `
| % {
$OutputFileName = Join-Path -Path $OutputFolder -ChildPath $_.FileName;
if (Test-Path $OutputFileName) {
$FileDirectoryName = [System.IO.Path]::GetDirectoryName($OutputFileName);
$FileNameWithoutExtension = [System.IO.Path]::GetFileNameWithoutExtension($OutputFileName);
$FileExtension = [System.IO.Path]::GetExtension($OutputFileName);
for ($i = 2; Test-Path $OutputFileName; $i++) {
$OutputFileName = "{0} ({1}){2}" -f (Join-Path -Path $FileDirectoryName -ChildPath $FileNameWithoutExtension), $i, $FileExtension;
}
}
Write-Host $OutputFileName;
$_.SaveAsFile($OutputFileName)
}
Remove-Item -Path C:\tests\*.jpg
Remove-Item -Path C:\tests\*.png
Start-Process –FilePath “c:\tests\*.docx” –Verb Print -PassThru
Start-Process –FilePath “c:\tests\*.xlsx” –Verb Print -PassThru
Start-Process –FilePath “c:\tests\*.doc” –Verb Print -PassThru
Start-Process –FilePath “c:\tests\*.xls” –Verb Print -PassThru
Start-Process –FilePath “c:\tests\*.pptx” –Verb Print -PassThru
Start-Process –FilePath “c:\tests\*.ppt” –Verb Print -PassThru
Start-Process –FilePath “c:\tests\*.xls” –Verb Print -PassThru
Start-Process –FilePath “c:\tests\*.msg” –Verb Print -PassThru
Start-Process –FilePath “c:\tests\*.xlsm” –Verb Print -PassThru
Start-Process –FilePath “c:\tests\*.rtf” –Verb Print -PassThru
Start-Process –FilePath “c:\tests\*.pdf” –Verb Print -PassThru `
%{sleep 3;$_}
Remove-Item -Path C:\tests\*.*
This accomplishes what i need, i might put a kill process in after each one just to make sure there is no doc stuck.
But - The 1 thing left to accomplish is i need this to write to a non default printer and not change the existing default? This runs on a server with a vbscript already running utilizing default printer so it will mess that up if it changes.
As usual with COM Objects, it's pretty ugly to do.
You're supposed to do it like the question here, but I can't get that to work at all. $Inbox.Folders['FolderName'] returns nothing, and $Inbox.Folders('FolderName') returns an error.
Here's how I can get it to work. I'm on PowerShell v4 with Office 2013.
Say you've got a folder at \\Inbox\eReports\Amazon\StatsReports, and you want all the messages in it.
$Messages = $inbox.Folders `
| ? Name -eq 'eReports' `
| % Folders `
| ? Name -eq 'Amazon' `
| % Folders `
| ? Name -eq 'StatsReports' `
| % Items;
Note that the way I'm using ForEach-Object and Where-Object require PowerShell v3. Under earlier versions this would be considerably more verbose.
Here's a full version of the script that works for me on Win 7 x64/PowerShell v4/Office 2013. I've tested it on a few different folders, so it should work.
It will automatically rename files with duplicate names, following the Windows convention of adding a (2), then a (3) and so on.
$OutputFolder = 'C:\OutputFolder';
$outlook = New-Object -ComObject Outlook.Application;
$olFolderInbox = 6;
$ns = $outlook.GetNameSpace("MAPI");
$inbox = $ns.GetDefaultFolder($olFolderInbox);
$inbox.Folders `
| ? Name -eq 'eReports' `
| % Folders `
| ? Name -eq 'Amazon' `
| % Folders `
| ? Name -eq 'StatsReports' `
| % Items `
| % Attachments `
| % {
$OutputFileName = Join-Path -Path $OutputFolder -ChildPath $_.FileName;
if (Test-Path $OutputFileName) {
$FileDirectoryName = [System.IO.Path]::GetDirectoryName($OutputFileName);
$FileNameWithoutExtension = [System.IO.Path]::GetFileNameWithoutExtension($OutputFileName);
$FileExtension = [System.IO.Path]::GetExtension($OutputFileName);
for ($i = 2; Test-Path $OutputFileName; $i++) {
$OutputFileName = "{0} ({1}){2}" -f (Join-Path -Path $FileDirectoryName -ChildPath $FileNameWithoutExtension), $i, $FileExtension;
}
}
Write-Host $OutputFileName;
$_.SaveAsFile($OutputFileName);
}

cls on a Get-Content -Wait call.

Is it possible (if so how) to clear my screen (cls) when my command
Get-Content -Path [path location] -Tail 1 -wait
sees that the file has been modified before printing the change.
I don't think Get-Content has this functionality but it shouldn't be hard to implement manually. Example:
$old = $null
while ($true) {
$new = Get-Content -Path $path -Tail 1
if ($new -ne $old) {
Clear-Host
Write-Host $new
$old = $new
}
Start-Sleep -Seconds 1
}
To output all added lines:
$old = [String]::Empty
while ($true) {
$new = Get-Content -Path $path
if ($new.Count -ne $old.Count) {
Clear-Host
Compare-Object -ReferenceObject $old -DifferenceObject $new `
| Select-Object -ExpandProperty "InputObject"
$old = $new
}
Start-Sleep -Seconds 1
}