Pablo's Powershell Pow-Wow

Discussion in 'Business & Enterprise Computing' started by PabloEscobar, Sep 18, 2014.

  1. DonutKing

    DonutKing Member

    Joined:
    Mar 21, 2004
    Messages:
    1,197
    Location:
    Tweed/Gold Coast
    It looks like you imported the CSV into an object called $groups (plural) but your next line is operating on $group (singular).

    Code:
    foreach ($group in $group)...
    Should have been

    Code:
    foreach ($group in $groups)...
    I suspect you previously imported the CSV file with all the groups into $group so it was not overwritten when you imported the CSV into $groups.
     
  2. looktall

    looktall Working Class Doughnut

    Joined:
    Sep 17, 2001
    Messages:
    24,408
    that's a typo in my post.

    the command was definitely $group in $groups.
     
  3. OP
    OP
    PabloEscobar

    PabloEscobar Member

    Joined:
    Jan 28, 2008
    Messages:
    12,929
    -whatif

    Learn it,
    Live it,
    Love it.

     
    Bengareth and freaky_beeky like this.
  4. looktall

    looktall Working Class Doughnut

    Joined:
    Sep 17, 2001
    Messages:
    24,408
    I came this close to using -whatif but I figured "nah it's just one group that won't matter if I fuck it up".

    I got lucky in this case.
     
  5. Ravennoir

    Ravennoir Member

    Joined:
    May 1, 2007
    Messages:
    6,397
    Location:
    Melbourne
    Until you forget you put it on a line in the script and wonder why nothing happening :)

    I figured out why my function wasnt working

    I had the output in the wrong foreach loop, moved it up one and it worked well

    Now I have to work out all the other parts
     
  6. freaky_beeky

    freaky_beeky Member

    Joined:
    Dec 2, 2004
    Messages:
    1,123
    Location:
    Brisbane
    That's when you use -Confirm (like in looktall's example). You press go, and it says "doing blah on thing" and you say yes, it then asks you about a doing "blah on newthing", and you realise your mistake, and hopefully before anything is broken.
     
  7. bcann

    bcann Member

    Joined:
    Feb 26, 2006
    Messages:
    5,429
    Location:
    NSW
    Gday All,

    I have some powershell code that i need to run on a RDS Server across all user sessions (Basically a HR message balloon popup with some whiney HR message for all users to barf over) How can i get this to run as a scheduled task simultaneously across all RDS Sessions?
     
  8. OP
    OP
    PabloEscobar

    PabloEscobar Member

    Joined:
    Jan 28, 2008
    Messages:
    12,929
    I can't think of any nice way of doing this.

    I'd probably end up with an agent type process that runs on startup, and polls for message.txt every 5 minutes, and then shits it all over the screen when it finds a change.
     
  9. DonutKing

    DonutKing Member

    Joined:
    Mar 21, 2004
    Messages:
    1,197
    Location:
    Tweed/Gold Coast
    Assuming you want to run it at a specific time for all users: Can you load the script as a scheduled task, under User preferences in group policy?
    Set it to run as %LogonDomain%\%LogonUser% and run only when user is logged on. Make sure to tick 'run in user context' under the Common tab.


    If you need to display messages ad-hoc, can you use Send-RDUserMessage from the RemoteDesktop module? You can use qwinsta command to get the list of user sessions from the server, parse its output and loop through it.
     
  10. bcann

    bcann Member

    Joined:
    Feb 26, 2006
    Messages:
    5,429
    Location:
    NSW
    after a fair bit of googling as HR wants it to display at a specific time (IE 11am), i can't just call it via a startup script. But i did find out that if you want it to run "Consoleless" you need to call it via ... VB Script....

    So setup a scheduled task to call the VB Script to call the Powershell to remain consoleless....

    command = "powershell.exe -nologo -command C:\HR-Message\HR-Message.ps1"
    set shell = CreateObject("WScript.Shell")
    shell.Run command,0

    And just because you guys may need it one day here is the powershell script that i grabbed from someone else on the net and customised.... please try not to cry as i am so not a scripter, but basically it reads from a .csv and randomly picks a quote and displays it via a popup bubble, yes i know its as ugly as sin, but again i suck @ powershell

    Function Invoke-BalloonTip {
    <#
    .Synopsis
    Display a balloon tip message in the system tray.
    .Description
    This function displays a user-defined message as a balloon popup in the system tray. This function
    requires Windows Vista or later.
    .Parameter Message
    The message text you want to display. Recommended to keep it short and simple.
    .Parameter Title
    The title for the message balloon.
    .Parameter MessageType
    The type of message. This value determines what type of icon to display. Valid values are
    .Parameter SysTrayIcon
    The path to a file that you will use as the system tray icon. Default is the PowerShell ISE icon.
    .Parameter Duration
    The number of seconds to display the balloon popup. The default is 1000.
    .Inputs
    None
    .Outputs
    None
    .Notes
    NAME: Invoke-BalloonTip
    VERSION: 1.0
    AUTHOR: Boe Prox
    #>


    [CmdletBinding()]
    Param (
    [Parameter(HelpMessage="The message title")]
    [string]$Title="Attention $env:username",

    [Parameter(HelpMessage="The message type: Info,Error,Warning,None")]
    [System.Windows.Forms.ToolTipIcon]$MessageType="Info",

    [Parameter(HelpMessage="The path to a file to use its icon in the system tray")]
    [string]$SysTrayIconPath='C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe',

    [Parameter(HelpMessage="The number of milliseconds to display the message.")]
    [int]$Duration=5000
    )

    Add-Type -AssemblyName System.Windows.Forms

    If (-NOT $global:balloon) {
    $global:balloon = New-Object System.Windows.Forms.NotifyIcon

    #Mouse double click on icon to dispose
    [void](Register-ObjectEvent -InputObject $balloon -EventName MouseDoubleClick -SourceIdentifier IconClicked -Action {
    #Perform cleanup actions on balloon tip
    Write-Verbose 'Disposing of balloon'
    $global:balloon.dispose()
    Unregister-Event -SourceIdentifier IconClicked
    Remove-Job -Name IconClicked
    Remove-Variable -Name balloon -Scope Global
    })
    }

    $importpath = "C:\hr-message\HR-Message.csv"
    $count = 1
    $list = Import-csv -Path $importpath | select -Expandproperty Message
    $Message = get-random -Inputobject $list -Count $count

    #Need an icon for the tray
    $path = Get-Process -id $pid | Select-Object -ExpandProperty Path

    #Extract the icon from the file
    $balloon.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($SysTrayIconPath)

    #Can only use certain TipIcons: [System.Windows.Forms.ToolTipIcon] | Get-Member -Static -Type Property
    $balloon.BalloonTipIcon = [System.Windows.Forms.ToolTipIcon]$MessageType
    $balloon.BalloonTipText = $Message
    $balloon.BalloonTipTitle = $Title
    $balloon.Visible = $true

    #Display the tip and specify in milliseconds on how long balloon will stay visible
    $balloon.ShowBalloonTip($Duration)

    Write-Verbose "Ending function"

    }

    Add-Type -AssemblyName System.Windows.Forms
    Invoke-BalloonTip -Title 'Attention!' -MessageType Info
     
  11. miicah

    miicah Member

    Joined:
    Jun 3, 2010
    Messages:
    5,794
    Location:
    Brisbane, QLD
    Before I start, the script I wrote works. I just want to know if it is possible to condense the section inside the IF statement, and if it's actually worth doing?

    Code:
    $wsDetails = Get-ADComputer -Filter * -SearchBase $labDetails -Properties Description
    
    #Start new CimSession using the Lab list we grabbed before
    $CIMList = New-CimSession -ComputerName $wsDetails.Name -Credential $creds -Authentication Negotiate -Name remoteWS
    
    foreach ($CIMObject in $CIMList)
    {
        for ($i = 0; $i -le $wsDetails.Count; $i++)
        {
            if ($CIMObject.ComputerName -eq $wsDetails[$i].Name)
            {
                $currentWS = Get-CimInstance -ComputerName $CIMObject.ComputerName -ClassName Win32_OperatingSystem
                $currentWS | Set-CimInstance -Property @{Description = $wsDetails.Description[$i]}
                $newDescription = $currentWS | Select-Object -ExpandProperty Description
    
                "Description updated for $($CIMObject.ComputerName). Now set to: $($newDescription)"           
                Break;
            }
        }
    }
     
  12. freaky_beeky

    freaky_beeky Member

    Joined:
    Dec 2, 2004
    Messages:
    1,123
    Location:
    Brisbane
    Just to make sure i'm reading this right, you're just updating the computers' description to the value stored in the computers AD accounts description field?

    Out of curiosity, what monitoring system do you use in your environment? (e.g. SCOM)
     
  13. miicah

    miicah Member

    Joined:
    Jun 3, 2010
    Messages:
    5,794
    Location:
    Brisbane, QLD
    Yes that's correct. And I think we (not you specifically) went through this in another thread, I work in education and the way that SCOM is set up here, it's almost impossible for them to give us permissions to do this kind of thing.

    So I have to find creative ways to do simple MS tasks.
     
  14. freaky_beeky

    freaky_beeky Member

    Joined:
    Dec 2, 2004
    Messages:
    1,123
    Location:
    Brisbane
    Yeah, I was going to suggest you write a quick SCOM management pack to do the exact thing, so that instead of having to run this against all your machines, you instead make all your machines do it themselves or alert.

    As for your code, the ';' after Break is superfluous and inconsistent with the remainder of your code.

    I expect you could possibly speed up the whole thing, with some filtering for online machines with remote CIM configured, via some testing using Test-NetConnection or Test-Connection, depending on how clean your AD is.

    Otherwise, I don't think you'd get a much faster.

    You may also want to consider putting a Try and Catch around that Set-CIMInstance, (or everything), in case you get some permission denied (or other weird errors).

    Also, just re-reading through, does $newdescription actually get updated to the new description?

    Shouldn't it be something like
    Code:
    $currentWS = $currentWS | Set-CimInstance -Property @{Description = $wsDetails.Description[$i]} -PassThru
    $newDescription = $currentWS | Select-Object -ExpandProperty Description
    
    Otherwise $newDescription is just getting the value of the "currentWS" description, which *may* not be the same as the one you've just updated?
     
    miicah likes this.
  15. miicah

    miicah Member

    Joined:
    Jun 3, 2010
    Messages:
    5,794
    Location:
    Brisbane, QLD
    $currentWS gets piped to Set-CimInstance which is when the description gets updated. So I hope that continuing to use that object will be up to date. I believe it works as I have tested it with a few different AD groups.
     
  16. tensop

    tensop Member

    Joined:
    Mar 26, 2002
    Messages:
    1,271
    OK, got one my brain simply cant figure out how to get started on

    I have a group named GS-SRT, with the HomePhone attribute populated with TWI.
    I have a user with a samaccountnamed John Twibbles, with the EmployeeID attribute populated with TWI.

    the unique match between the group and the user is the HomePhone/EmployeeID

    How the hell do i script it to add a user to the group where the two fields match?

    My brain is too cooked, can't even figure out how to explain this one :p
     
    Last edited: Mar 9, 2019
  17. OP
    OP
    PabloEscobar

    PabloEscobar Member

    Joined:
    Jan 28, 2008
    Messages:
    12,929
    Whats TWI?

    If $user.employeeid -eq $group.HomePhone then
    Add-Adgroupmember -identity $Group -members $User
     

Share This Page