Screenshot
I decided to try and create a Powershell script. To remove printers that are not in the $StandardPrinterListe. This has been working for about a week and then yesterday it doesn't work anymore. It stops after checking a couple of computers. I would appreciate any help on this matter. If you feel like you also could give input on how the script could have been done better, please let me know.
$Publikum = New-Object Collections.Generic.List[string]
$PublikumOnline = New-Object Collections.Generic.List[string]
$PublikumOffline = New-Object Collections.Generic.List[string]
$PrintListe = New-Object Collections.Generic.List[string]
$PrinterLokal = New-Object Collections.Generic.List[string]
$PrinterLokalFjernes = New-Object Collections.Generic.List[string]
$StandardPrinterListe = New-Object Collections.Generic.List[string]
$StandardPrinterListe = #('Microsoft Print to PDF', 'Send til OneNote 16', 'Microsoft XPS Document Writer', 'Fax','Send to OneNote 16')
$i = 0
foreach($c in Get-ADComputer -Filter {Name -like "*Name*"} -searchbase "Some SearchBase"){
$Publikum.Add($c.Name)
}
foreach($Element in $Publikum){
Write-Progress -Activity "Sjekker offline status" -Status "Progress:" -PercentComplete ($i/$Publikum.count*100)
Write-Host $Element
if (Test-Connection -ComputerName $Element -Quiet)
{
$PublikumOnline.Add($Element)
}
else
{
$PublikumOffline.Add($Element)
}
$i = $i+1
Write-Host $PublikumOffline.Count "Offline" -BackgroundColor “Red”
Write-Host $PublikumOnline.Count "Online" -ForegroundColor “Green”
}
$Left = $PublikumOnline.Count
$i = 0
foreach($Element in $PublikumOnline){
$PrintResultat = Invoke-Command -ComputerName $Element -ScriptBlock {
$Print = #{}
$Print.LokalPrint = Get-Printer
New-Object psobject -property $Print
}
foreach ($Printer in $PrintResultat.LokalPrint) {
if($Printer.Name -notin $StandardPrinterListe){
$PrinterLokalFjernes.Add($Printer.Name)
}
$PrinterLokal.Add($Printer.Name)
}
Write-Output $Element $PrinterLokal
if ($PrinterLokalFjernes)
{
foreach ($FjernePrinter in $PrinterLokalFjernes){
Write-Host $Element $FjernePrinter -BackgroundColor “Red”
}
. 'C:\Users\jonhstor-drift\Documents\Fjerne Lokale skrivere.ps1'
Fjern-Skriver -Session ([ref]$Element) -Target ([ref]$PrinterLokalFjernes)
}
else
{
Write-Host $Element "Har ikke pushprint" -ForegroundColor “Green”
}
$PrinterLokalFjernes.Clear()
$PrinterLokal.Clear()
$i = $i+1
$Left = $Left - 1
Write-Host $Left "igjen å sjekke"
Write-Progress -Activity "Progresjon" -Status "Progress:" -PercentComplete ($i/$PublikumOnline.count*100)
}
Read-Host -Prompt "Press Enter to exit"
function Fjern-Skriver([ref]$Session, [ref]$Target) {
foreach($Element in $Target.Value){
Invoke-Command -ComputerName $Session.Value -ScriptBlock {
C:\Windows\SysWOW64\rundll32.exe printui.dll,PrintUIEntry /n $using:Element /dl
Gpupdate /force
}
Write-Host "Har fjernet" $Element "fra maskin" $Session.Value -ForegroundColor “Green”
}
}
I have the following code, which logs into a site that I use frequently:
param(
[string]$interval
)
function Refresh-WebPages {
"Neptun refresh every $interval seconds."
"press any key to exit."
$shell = New-Object -ComObject Shell.Application
do {
Start-Sleep -Seconds $interval
'Refreshing'
$shell.Windows() |
Where-Object { $_.Document.url } |
ForEach-Object { $_.Refresh() }
} until ( [System.Console]::KeyAvailable )
[System.Console]::ReadKey($true) | Out-Null
}
$username = "asd";
$SecureString = Read-Host "password" -AsSecureString;
$BSTR =
[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureString);
$PlainPassword =
[System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
$IE=new-object -com internetexplorer.application;
$IE.navigate2("https://hallgato.neptun.elte.hu/login.aspx");
$IE.visible=$true;
While ($IE.Busy -eq $true) {Start-Sleep -Milliseconds 500}
$IE.Document.getElementById('user').value = "$username";
$IE.Document.getElementById('pwd').value = "$PlainPassword";
($IE.document.getElementById('btnSubmit') |select -first 1).click();
Refresh-WebPages -interval
I want to check if the login have failed or succeeded. Can I check if the URL is different somehow?
I am working on a script to allow my sys admins to make changes to an ACL without having to drill down to the folder level. So far, everything is executing as intended except for my first "If..Else" statement in my first switch. It gets skipped entirely and moves on to asking for the account name and I cannot figure out why.
Does anyone have any ideas?
$account = $null
$accesslevel = $null
$accesstype = $null
$acl = $null
$title = Write-Host "Modify ACL" -ForegroundColor Green
$message = Write-Host "Select the action to initiate:" -ForegroundColor Cyan
$add = New-Object System.Management.Automation.Host.ChoiceDescription "&Add Permissions", "Add Permissions"
$remove = New-Object System.Management.Automation.Host.ChoiceDescription "&Remove Permissions", "Remove Permissions"
$options = [System.Management.Automation.Host.ChoiceDescription[]]($add, $remove)
$selectAction = $Host.UI.PromptForChoice($title, $message, $options, 0)
switch($selectAction){
0{
$pathPrompt = Write-Host "Please enter path to file/folder:" -ForegroundColor Green
$path = Read-Host
$test = Test-Path $path | Out-Null
if($test -eq $false){
Write-Host "ERROR! Invalid Path!" -ForegroundColor Red
Break
}Else{
Write-Host "Getting ACL on`r"$path -ForegroundColor Green
$acl = get-acl $path
}
if($account -eq $null){
Write-Host "Enter Account (ex. Domain\Account)" -ForegroundColor Green
$account = Read-Host
}
$title2 = Write-Host "Permission Levels" -ForegroundColor Green
$message2 = Write-Host "Select the appropriate permissions to apply:" -ForegroundColor Cyan
$fullControl = New-Object System.Management.Automation.Host.ChoiceDescription "&FullControl", "FullControl"
$modify = New-Object System.Management.Automation.Host.ChoiceDescription "&Modify", "Modify"
$readExecute = New-Object System.Management.Automation.Host.ChoiceDescription "&ReadAndExecute", "ReadAndExecute"
$read = New-Object System.Management.Automation.Host.ChoiceDescription "&Read", "Read"
$write = New-Object System.Management.Automation.Host.ChoiceDescription "&Write", "Write"
$readWrite = New-Object System.Management.Automation.Host.ChoiceDescription "&Read, Write", "Read, Write"
$list = New-Object System.Management.Automation.Host.ChoiceDescription "&List", "List"
$options2 = [System.Management.Automation.Host.ChoiceDescription[]]($fullControl, $modify, $readExecute, $read, $write, $readWrite, $list)
do{
$selectAction2 = $Host.UI.PromptForChoice($title2, $message2, $options2, 1)
switch($selectAction2){
0{$accesslevel = 'FullControl'}
1{$accesslevel = 'Modify'}
2{$accesslevel = 'ReadandExecute'}
3{$accesslevel = 'Read'}
4{$accesslevel = 'Write'}
5{$accesslevel = 'Read, Write'}
6{$accesslevel = 'List'}
}
}Until($accesslevel -ne $null)
$title3 = Write-Host "Access Type" -ForegroundColor Green
$message3 = Write-Host "Select the type of access:" -ForegroundColor Cyan
$allow = New-Object System.Management.Automation.Host.ChoiceDescription "&Allow", "Allow"
$deny = New-Object System.Management.Automation.Host.ChoiceDescription "&Deny", "Deny"
$options3 = [System.Management.Automation.Host.ChoiceDescription[]]($allow, $deny)
do{
$selectAction3 = $Host.UI.PromptForChoice($title3, $message3, $options3, 0)
switch($selectAction3){
0{$accesstype = 'Allow'}
1{$accesstype = 'Deny'}
}
}Until($accesstype -ne $null)
Write-Host "Setting ACL on"$path -ForegroundColor Yellow
$arguments = $account, $accesslevel, $accesstype
Try{
$accessrule = New-Object System.Security.AccessControl.FileSystemAccessRule $arguments
$acl.SetAccessRule($accessrule)
}Catch{
Write-Host "Exception thrown : $($error[0].exception.message)"
}Finally{
$acl | set-acl $path
}
Write-Host "ACL settings have been completed." -ForegroundColor Cyan
}
1{
$pathPrompt
$path
$test | Out-Null
if($test -eq $false){
Write-Host "ERROR! Invalid Path!" -ForegroundColor Red
Break
}Else{
Write-Host "Getting ACL on`r"$path -ForegroundColor Green
$acl = get-acl $path
}
if($account -eq $null){
$account = Read-Host "Enter Account (ex. Domain\Account)" -ForegroundColor Green
}
}
}
Your if-else is working correctly as you have written it. What you have written, however, is not what you want.
First: In the Write-Host in the else clause, you do not want to use the escaped `r; you want to use an escaped `n, or perhaps nothing at all. `r indicates a return-to-start-of-line but not go-to-next-line; `n indicates return-to-start-of-line-and-go-to-next-line. The repeating of the entered path in green in your example above is a strong hint that that Write-Host is being executed.
Second, your Test-Path causes $test to have no value, because you are sending the results to the null device instead of allowing it to be returned to the statement for assignment to the variable. Remove the | Out-Null.
I found very helpful informations to get started with the script here:
http://blogs.technet.com/b/heyscriptingguy/archive/2010/04/06/hey-scripting-guy-how-can-i-add-custom-properties-to-a-microsoft-word-document.aspx
But I just can't do the same for several Word documents - for exemple 3 or 4 word documents in the same folder.
I tried the command ForEach but I always got an error message.
Could someone help me how to modify the following script in order to take into consideration all the word documents in the path folder?
$path = "C:\fso\Test.docx"
$application = New-Object -ComObject word.application
$application.Visible = $false
$document = $application.documents.open($path)
$binding = "System.Reflection.BindingFlags" -as [type]
$customProperties = $document.CustomDocumentProperties
$typeCustomProperties = $customProperties.GetType()
$CustomProperty = "Client"
$Value = "My_WayCool_Client"
[array]$arrayArgs = $CustomProperty,$false, 4, $Value
Try {
$typeCustomProperties.InvokeMember(`
"add", $binding::InvokeMethod,$null,$customProperties,$arrayArgs) |
out-null
} Catch [system.exception] {
$propertyObject = $typeCustomProperties.InvokeMember(`
"Item", $binding::GetProperty, $null, $customProperties, $CustomProperty)
$typeCustomProperties.InvokeMember(`
"Delete", $binding::InvokeMethod, $null, $propertyObject, $null)
$typeCustomProperties.InvokeMember(`
"add", $binding::InvokeMethod, $null, $customProperties, $arrayArgs) |
Out-Null
}
$document.Saved = $false
$document.save()
$application.quit()
$application = $null
[gc]::collect()
[gc]::WaitForPendingFinalizers()
I also tried this
Get-ChildItem -path $path | Where-Object { $_.Name -like '*.docx' }
and the ForEach cmdlet.
As Matt suggested, I would put in a ForEach loop after the application is open. I would also add closing the current document within the ForEach loop. Something like:
$path = "C:\fso\*.docx"
$application = New-Object -ComObject word.application
$application.Visible = $false
ForEach($File in (GCI $path|Select -Expand FullName)){
$document = $application.documents.open($file)
$binding = "System.Reflection.BindingFlags" -as [type]
<Other Commands>
$document.Saved = $false
$document.save()
$document.Close()
}
$application.quit()
$application = $null
[gc]::collect()
[gc]::WaitForPendingFinalizers()
Here's how I was able to do it:
#Set the PATH variable to the location where you saved the script and CSV file
$path = "c:\temp\PowerShell Scripts\"
#Set the DOC variable to the location of the document you want to update
$doc = "c:\temp\test.docx"
$application = New-Object -ComObject word.application
$application.Visible = $false
$document = $application.documents.open($doc)
$binding = "System.Reflection.BindingFlags" -as [type]
$customProperties = $document.CustomDocumentProperties
$typeCustomProperties = $customProperties.GetType()
$CustomPropertiesWorklist = Import-Csv $path\args.csv
if($CustomPropertiesWorklist.Count){
for($i = 0; $i -lt $CustomPropertiesWorklist.Count; $i++)
{
$CustomProperty = $CustomPropertiesWorklist[$i].CP
$msoPropertyType = $CustomPropertiesWorklist[$i].Type
$Value = $CustomPropertiesWorklist[$i].Value
[array]$arrayArgs = $CustomProperty,$false,$msoPropertyType,$Value
Try
{
$typeCustomProperties.InvokeMember(`
"add", $binding::InvokeMethod,$null,$customProperties,$arrayArgs) |
out-null
}
Catch [system.exception]
{
$propertyObject = $typeCustomProperties.InvokeMember(`
"Item", $binding::GetProperty,$null,$customProperties,$CustomProperty)
$typeCustomProperties.InvokeMember(`
"Delete", $binding::InvokeMethod,$null,$propertyObject,$null)
$typeCustomProperties.InvokeMember(`
"add", $binding::InvokeMethod,$null,$customProperties,$arrayArgs) |
Out-Null
}
}
}
else
{
$CustomProperty = $CustomPropertiesWorklist.CP
$msoPropertyType = $CustomPropertiesWorklist.Type
$Value = $CustomPropertiesWorklist.Value
[array]$arrayArgs = $CustomProperty,$false,$msoPropertyType,$Value
Try
{
$typeCustomProperties.InvokeMember(`
"add", $binding::InvokeMethod,$null,$customProperties,$arrayArgs) |
out-null
}
Catch [system.exception]
{
$propertyObject = $typeCustomProperties.InvokeMember(`
"Item", $binding::GetProperty,$null,$customProperties,$CustomProperty)
$typeCustomProperties.InvokeMember(`
"Delete", $binding::InvokeMethod,$null,$propertyObject,$null)
$typeCustomProperties.InvokeMember(`
"add", $binding::InvokeMethod,$null,$customProperties,$arrayArgs) |
Out-Null
}
}
$document.Saved = $false
$document.save()
$application.quit()
$application = $null
[gc]::collect()
[gc]::WaitForPendingFinalizers()
I adapted and combined some of the solutions I found in this thread and others to create what I think is how a script like this should behave, i.e. change multiple custom properties in multiple word documents and automatically update the actual fields in the documents. Hopefully this will help others too!
You just need to change the list of properties that will be added / updated and set the path to the folder where your .docx files are, and it should handle the rest.
#Comment out (or remove, you barbarian) the properties that do not need updating
$propertiesToUpdate = #{
"Product Name" = "Amazing Product"
"Project Name" = "Best Project"
"Revision (Record)" = "01.00"
"Approved By (Record)" = "Me"
"Date Approved (Record)" = "10.03.2016"
}
#Update the path to the documents to update:
$path = "C:\path\*.docx"
Write-Host -ForegroundColor Cyan "Loading Application..."
$application = New-Object -ComObject word.application
$application.Visible = $false
function AddOrUpdateCustomProperty ($CustomPropertyName, $CustomPropertyValue, $DocumentToChange)
{
$customProperties = $DocumentToChange.CustomDocumentProperties
$typeCustomProperties = $customProperties.GetType()
$binding = "System.Reflection.BindingFlags" -as [type]
[array]$arrayArgs = $CustomPropertyName,$false, 4, $CustomPropertyValue
Try
{
$typeCustomProperties.InvokeMember("add", $binding::InvokeMethod,$null,$customProperties,$arrayArgs) | out-null
}
Catch [system.exception]
{
$propertyObject = $typeCustomProperties.InvokeMember("Item", $binding::GetProperty, $null, $customProperties, $CustomPropertyName)
$typeCustomProperties.InvokeMember("Delete", $binding::InvokeMethod, $null, $propertyObject, $null)
$typeCustomProperties.InvokeMember("add", $binding::InvokeMethod, $null, $customProperties, $arrayArgs) | Out-Null
}
Write-Host -ForegroundColor Green "Success! Custom Property:" $CustomPropertyName "set to value:" $CustomPropertyValue
}
ForEach($File in (GCI $path|Select -Expand FullName))
{
Write-Host -ForegroundColor Cyan "Opening Document..." $File
$document = $application.documents.open($File)
ForEach($property in $propertiesToUpdate.GetEnumerator())
{
AddOrUpdateCustomProperty $($property.Name) $($property.Value) $document
}
Write-Host -ForegroundColor Cyan "Updating document fields."
$document.Fields.Update() | Out-Null
Write-Host -ForegroundColor Cyan "Saving document."
$document.Saved = $false
$document.save()
$document.close()
}
$application.quit()
$application = $null
[gc]::collect()
[gc]::WaitForPendingFinalizers()
Write-Host -ForegroundColor Green "Done!"
I couldn't get the above to work. Always object.GetType() failed to retrieve anything, resulting in an error. This is what I got to work for BuiltIn properties; same would apply to custom properties:
#Properties to update (BuiltIn)
$propertyUpdates = #{
"Company" = "Company"
"Manager" = "Manager"
}
#Path to the documents to update:
$path = "C:\FilesToUpdate\*.docx"
Write-Host -ForegroundColor Cyan "Loading Application..."
$app = New-Object -ComObject Word.Application
$app.Visible = $false
ForEach($file in (GCI $path|Select -Expand FullName))
{
Write-Host -ForegroundColor Cyan "Opening document: " $file
$doc = $app.Documents.Open($file)
$binding = "System.Reflection.BindingFlags" -as [type]
Write-Host -ForegroundColor Cyan "Updating document properties..."
ForEach($p in $propertyUpdates.GetEnumerator())
{
Try {
$props = $doc.BuiltInDocumentProperties
$prop = [System.__ComObject].InvokeMember("Item", $binding::GetProperty, $null, $props, $p.Name)
[System.__ComObject].InvokeMember("Value", $binding::SetProperty, $null, $prop, $p.Value)
}
Catch [system.exception] {
write-host -ForegroundColor red "Value not found for $p.Name"
}
}
$doc.Fields.Update() | Out-Null
Write-Host -ForegroundColor Cyan "Saving document."
$doc.Saved = $false
$doc.save()
$doc.close()
}
$app.quit()
$app = $null
[gc]::collect()
[gc]::WaitForPendingFinalizers()
Write-Host -ForegroundColor Green "Done!"
I had develop a script that basically restart a service in a remove server based on a selection.
This selection is done by a form.
The problem is... when I run this using the ISE... the script work totally fine.
When I run this using the RIGHT CLICK / RUN with Powershell
My form doesn't work. The Button that I had created didn't appear...
What can be wrong?
Here is my code:
Function Write-Centered {
Param( [string] $message,
[string] $color = "black")
$offsetvalue = [Math]::Round(([Console]::WindowWidth / 2) + ($message.Length / 2))
Write-Host ("{0,$offsetvalue}" -f $message) -ForegroundColor $color
}
clear
$timestamp=Get-date -format yyyy_MM_dd_hh_mm_ss
$systems = #(
("System 1","Server1","bmc_ctsa_sm_SAP_Instance_2"),
("System 2","Server2","bmc_ctsa_sm_SAP_Instance_6"),
("System 3","Server3","bmc_ctsa_sm_SAP_Instance_6")
)
Write-Centered "Service Restart Tool" "Green"
Write-Centered "Choose the target system you would like to restart" "Green"
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
$Form1 = New-Object System.Windows.Forms.Form
$Form1.ClientSize = New-Object System.Drawing.Size(300, 100)
$form1.topmost = $true
$Form1.Controls.Add($Button)
$Form1.Text = "SSPR Restart Tool"
$Button = New-Object System.Windows.Forms.Button
$Button.Location = New-Object System.Drawing.Point(150, 25)
$Button.Size = New-Object System.Drawing.Size(120, 25)
$Button.add_Click({
$label.Text = $comboBox1.SelectedItem.ToString()
$Form1.Close()
})
$Button.Text = "Start Process"
$Label = New-Object System.Windows.Forms.Label
$Label.Location = New-Object System.Drawing.Point(10, 10)
$Label.Size = New-Object System.Drawing.Size(300, 15)
$Label.Text = "Please select the system you would like to restart"
$Form1.Controls.Add($Label)
$comboBox1 = New-Object System.Windows.Forms.ComboBox
$comboBox1.Location = New-Object System.Drawing.Point(10, 25)
$comboBox1.Size = New-Object System.Drawing.Size(120, 25)
foreach($system in $systems)
{
$comboBox1.Items.add($system[0]) | Out-Null
}
$Form1.Controls.Add($comboBox1)
$label = New-Object System.Windows.Forms.Label
$label.Location = New-Object System.Drawing.Point(70, 90)
$label.Size = New-Object System.Drawing.Size(98, 23)
$label.Text = ""
$Form1.Controls.Add($label)
[void]$form1.showdialog()
Write-Centered $comboBox1.Text "Yellow"
$do=0
$i=0
do {
if ($comboBox1.Text -eq $systems[$i][0]){
$result=$i
$i++
}
$do++
}while ($do -le $systems.length-1)
$System=$systems[$result][0]
$Server=$systems[$result][1]
$Instance=$systems[$result][2]
$yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", `
"Start the process."
$no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", `
"Cancel the process."
$options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)
$result = $host.ui.PromptForChoice("",`
"`nWould you like to progress with the service restart? `n`nSystem: $System`nServer: $Server`nInstance: $Instance", $options, 0)
if ($result -eq 0) {
$services = Get-Service -computername $Server -name $Instance
$target=$services.name
$sharefolder = "\\"+$Server+"\c$"
New-PSDrive –Name “X” –PSProvider FileSystem –Root $sharefolder | out-null
Write-Host ======================================================
Write-Host = Searching for the destination folder. Please wait...
Write-Host ======================================================
$test1=Test-Path "X:\Program Files (x86)\BMC Software"
$test2=Test-Path "X:\Program Files\BMC Software"
if ($test1) {
$file=Get-ChildItem "X:\Program Files (x86)\BMC Software" -recurse | Where-Object {$_.PSIsContainer -eq $true -and $_.Name -match "CONTROL-SA"}
} elseif ($test2){
$file=Get-ChildItem "X:\Program Files\BMC Software" -recurse | Where-Object {$_.PSIsContainer -eq $true -and $_.Name -match "CONTROL-SA"}
}
$fullname=$file.FullName+"\Services Manager\"+$Instance
$fullname
Write-Host ======================================================
Write-Host = Stopping $target
Write-Host ======================================================
Get-Service -Name $target -ComputerName $Server | Set-Service -Status Stopped
$src=$fullname+"\log\*"
$des=$fullname+"\log_bkp_"+$timestamp+"\"
Write-Host ======================================================
Write-Host = Perform LOG folder backup for troubleshooting
Write-Host ======================================================
New-Item $des -type directory | out-null
Move-item -path $src -destination $des -force -verbose
#Remove-item $src -force -recurse -verbose
Get-Service -Name $target -ComputerName $Server | Set-Service -Status Running
Remove-PSDrive -Name "X" | out-null
}
elseif ($result -eq 1) {
BREAK
}
Write-Host ======================================================
Write-Host = Process Completed
Write-Host = You may now close this window
Write-Host ======================================================
Start-Sleep -s 120
Have the screen captures of the results.. but low reputation prevent me to post it... :-(
I typo'd my comment, it should be Controls and not Controles, but that's the issue. After $Form1.Controls.Add($label) add a new line:
$Form1.Controls.Add($Button)
See if it doesn't work as expected at that time. It does for me when I tested it.
A wrong place for the $Form1.Controls.Add($Button) was preventing my code to show up the control button...
Thanks for the hint