Pablo's Powershell Pow-Wow

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

  1. NSanity

    NSanity Member

    Joined:
    Mar 11, 2002
    Messages:
    18,388
    Location:
    Brisbane
    setup bitbucket
    made git talk to bitbucket
    secured it with SSH
    decided nah fuck it, put it back to https because windows will cache that shit

    I R DEVOPS NOW
     
    Last edited: Dec 5, 2016
  2. Punk

    Punk Member

    Joined:
    Mar 15, 2002
    Messages:
    1,058
    Location:
    Walking on Sunshine
    So I got some more time to spend on that script and it's a totally different beast now.

    Exception logging,filtering for names and time as needed.
    What a great learning experience, nothing a bit of goggle searching can't fix. :thumbup:
     
  3. Ravennoir

    Ravennoir Member

    Joined:
    May 1, 2007
    Messages:
    6,507
    Location:
    Melbourne
    Hey Everyone,

    I have another head scratcher :)

    I need to create a script to pull Datastore usage from VMware

    I can get the info easy enough, the issue is I need to append the info to a file daily so it ends up like this

    Date, 12/12, 13/12, 14/12
    DS1, 70%, 71%, 71%
    DS2, 60%, 62%, 65%
    DS2, 65%, 60%, 60%

    The end goal will be that at the end of the month, the average will be worked out
     
  4. OP
    OP
    PabloEscobar

    PabloEscobar Member

    Joined:
    Jan 28, 2008
    Messages:
    14,611
    /TrollElvis

    http://ramblingcookiemonster.github.io/PSExcel-Intro/

    Store it in Excel :).

    /EndTroll


    I've got a feeling that you're doing it wrong. But its also 5 O'clock, so I can't quantify it.

    Of the top of my head, I'd be loading the CSV into a custom object. adding the current days data to it, and then dumping the WHOLE object back out to a file.

    You can use out-file -append to write additional lines to a file, but I'm not sure you can use Export-CSV to add new rows to a CSV.
     
  5. Ravennoir

    Ravennoir Member

    Joined:
    May 1, 2007
    Messages:
    6,507
    Location:
    Melbourne
    Yeah I think I am, and I had the same thought so I went home, Ill look again tomorrow :)
     
  6. freaky_beeky

    freaky_beeky Member

    Joined:
    Dec 2, 2004
    Messages:
    1,169
    Location:
    Brisbane
    As Pablo suggested, you can indeed append to a csv file with export-csv (using the -append parameter).

    For your data, rather than format like you originally stated e.g.:
    Code:
    Date, 12/12, 13/12, 14/12
    DS1, 70%, 71%, 71%
    DS2, 60%, 62%, 65%
    DS2, 65%, 60%, 60%
    
    I think you'll find it a lot easier if you formatted this way instead
    Code:
    Date, DS1, DS2, DS3
    12/12, 70%, 60%, 65%
    13/12, 71%, 62%, 60%
    14/12, 71%, 65%, 60%
    
    The way I'd look at scripting it would be to create a custom object (or use an existing one if you can get all the properties you want) with the properties Date, DS1, DS2...DS(x) and then just append that object to the existing CSV each time you run it.
     
  7. Ravennoir

    Ravennoir Member

    Joined:
    May 1, 2007
    Messages:
    6,507
    Location:
    Melbourne
    I did think of doing that, but I was wondering if there then would be a way to get the average down each column at the end of the month
     
  8. freaky_beeky

    freaky_beeky Member

    Joined:
    Dec 2, 2004
    Messages:
    1,169
    Location:
    Brisbane
    Something like this:


    Code:
    #requires -version 2.0
    
    #Set Strict Mode (option explicit VBS)
    Set-StrictMode -Version 2.0
    
    #Path to CSV to input
    $csvPath = 'C:\temp\ravennoir.csv'
    
    #Import the CSV
    $csvImport = Import-csv -Path $csvPath
    
    #Get all the data stores (all properties that begin with DS followed by an integer)
    $dataStores = $csvImport | Get-Member -MemberType Properties | Select-Object -ExpandProperty Name | Where-Object {$_ -match '^DS\d+$'}
    
    #iterate through each datastore
    foreach ($dataStore in $dataStores)
    {
        [int]$total = $null #ensure value is clear for each iteration
        #Iterate through each value for each datastore and add them to a total
        $total = $csvImport.$dataStore | Measure-Object -Sum | Select-Object -ExpandProperty Sum
    
        #Create a new variable with a dynamic name in the format of Data Store Name (e.g. DS1) appended by Average, e.g. DS1Average
        #The Value is the total divided by the members (the mean value) rounded to 2 decimal places
        New-Variable -Name "$dataStore`Average" -Value $("{0:N2}" -f ($total/$csvImport.$dataStore.Count)) -Force
    }
    
    #Output all DS*Averages
    Get-Variable -Name "DS*Average"
    
    Output:
    Code:
    Name                           Value                                                                                                                                                                                                
    ----                           -----                                                                                                                                                                                                
    DS1Average                     70.67                                                                                                                                                                                                
    DS2Average                     62.33                                                                                                                                                                                                
    DS3Average                     61.67
    
    ravennoir.csv
    Code:
    Date,DS1,DS2,DS3
    12/12/2016,70,60,65
    13/12/2016,71,62,60
    14/12/2016,71,65,60
    
    EDIT:

    If you don't need decimal places measure-object has an -average parameter you could use, which would then replace the total variable with a variable $average e.g. the foreach loop becomes

    Code:
    #iterate through each datastore
    foreach ($dataStore in $dataStores)
    {
        [int]$average = $null #ensure value is clear for each iteration
        #Iterate through each value for each datastore and discover the average
        $average = $csvImport.$dataStore | Measure-Object -Average | Select-Object -ExpandProperty Average
    
        #Create a new variable with a dynamic name in the format of Data Store Name (e.g. DS1) appended by Average, e.g. DS1Average
        #The Value is the average
        New-Variable -Name "$dataStore`Average" -Value $average -Force
    }
    
    EDIT2:

    Woops, because i typecast'd $average as an int it doesn't have decimal places... obviously if you use something that supports decimal places (e.g. double) you can use the average parameter and still have the decimal places...
     
    Last edited: Dec 13, 2016
  9. Luke212

    Luke212 Member

    Joined:
    Feb 26, 2003
    Messages:
    10,206
    Location:
    Sydney
    i found it annoying there is no download package for chocolatey, you have to install it via powershell, like:

    @powershell -NoProfile -ExecutionPolicy Bypass -Command "iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))" && SET PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin

    very un-user friendly!
     
  10. NSanity

    NSanity Member

    Joined:
    Mar 11, 2002
    Messages:
    18,388
    Location:
    Brisbane
    you are like... the Donald Trump, of IT.
     
  11. freaky_beeky

    freaky_beeky Member

    Joined:
    Dec 2, 2004
    Messages:
    1,169
    Location:
    Brisbane
    Does this do what you want?

    https://msdn.microsoft.com/powershell/reference/5.1/PackageManagement/Get-PackageProvider

    Specifically
    Code:
    Get-PackageProvider -Name "Chocolatey"
    
    Or if you want a step by step guide?
     
  12. Luke212

    Luke212 Member

    Joined:
    Feb 26, 2003
    Messages:
    10,206
    Location:
    Sydney
  13. OP
    OP
    PabloEscobar

    PabloEscobar Member

    Joined:
    Jan 28, 2008
    Messages:
    14,611
    What, If Anything are people using to provide Mook-Level access to their scripts?

    I've got some scripts (and ideas) that I would like to provide to the rest of IT (and to the Wider Organization), But running a PS1 from your desktop will not pass muster an an acceptable method for many of the non-technical business units we've got.

    We have Orchestrator in place, but it's a shitful system when it comes to powershell, because of the limitations it imposes, it makes doing things quickly incredibly difficult.

    I've been toying with the Idea of Jenkins - https://hodgkins.io/automating-with-jenkins-and-powershell-on-windows-part-1 but again, Without serious work, It's not going to Pass UAC.

    So I throw the floor open...

    If you've got a script that makes the coffee... how do you allow others to access it, so they can make their own coffee?
     
  14. Ravennoir

    Ravennoir Member

    Joined:
    May 1, 2007
    Messages:
    6,507
    Location:
    Melbourne

    Mostly I have things setup as tasks, and just have people add details to a spreadsheet and let the task run overnight

    a friend of mine has setup scripts previously that are locked down, so they can only be edited by the right people, I just dont remember how he did it
     
  15. OP
    OP
    PabloEscobar

    PabloEscobar Member

    Joined:
    Jan 28, 2008
    Messages:
    14,611
    What about for on-demand things?
     
  16. Ravennoir

    Ravennoir Member

    Joined:
    May 1, 2007
    Messages:
    6,507
    Location:
    Melbourne
    That would normally come to our team anyway

    I would say that most of my scripts are to make my job easier, not anyone elses :p
     
  17. freaky_beeky

    freaky_beeky Member

    Joined:
    Dec 2, 2004
    Messages:
    1,169
    Location:
    Brisbane
    I have done this a number of different ways.

    For example, create an install script that installs the script to a known location e.g. Program Files (so they can't modify the script, not that it matters as I use code signing as well).
    I also ensure that I create a shortcut on the local users (or all users desktop), but you could create one anywhere, with a pretty icon called "Connect Phone" or whatever it is. The user then just runs it and it works.

    Sample code:
    Code:
    <#
    .Synopsis
       Install the custom PS1 application "Connect Phone"
    .DESCRIPTION
       Install the custom PS1 application "Connect Phone".
    
       Copy the PS1 and Icon file to (32 bit) program files in the respective folder.
       Generate a shortcut on the All Users desktop that points to the PS1 and uses the
       respective icon copied to the same location.
    
       If Uninstall is specified, delete the created folder and all files
    .EXAMPLE
       Install_ConnectPhone.ps1
    .EXAMPLE
       Install_ConnectPhone.ps1 -Uninstall
    .NOTES
       General notes
    #>
    Param
    (
        # If specified run the uninstall process, instead of the install process
        [Parameter(Mandatory=$false, 
                    ValueFromPipeline=$true,
                    ValueFromPipelineByPropertyName=$true, 
                    ValueFromRemainingArguments=$false)]
        [switch]$Uninstall
    )
    
    #Set the strictmode to the latest available (to ensure PS1+ compatibility)
    Set-StrictMode -Version Latest
    
    #Variable Declaration
    [string]$installDir = 'Phone Updater'
    [string]$icon = 'Connect_Phone.ico'
    [string]$application = 'Connect_Phone.ps1'
    [string]$shortcutPath = "$env:ALLUSERSPROFILE\Desktop\Connect Phone.lnk"
    [bool]$result = $false
    #End Variable Declaration
    
    Write-Verbose -Message "Starting Script"
    
    #If the version of PowerShell is greater than 2 this already exists, otherwise generate it from less ideal means
    if (!(Get-Variable -Name PSScriptRoot -ErrorAction SilentlyContinue))
    {
        Write-Verbose -Message 'PSScriptRoot variable does not exist, creating it'
        $PSScriptRoot = $MyInvocation.Mycommand.path | Split-Path
    }
    
    #If the computer is running AMD64 (64bit architecture) install the application into Program Files(x86)
    if($env:PROCESSOR_ARCHITECTURE -notmatch 'AMD64')
    {
        Write-Verbose -Message 'Architecture is 32bit'
        $installDir = "$env:ProgramFiles\$installDir"
    }
    else
    {
        Write-Verbose -Message 'Architecture is 64bit'
        $installDir = "${env:ProgramFiles(x86)}\$installDir"
    }
    
    if($Uninstall)
    {
        #THIS IS THE CODE FOR THE UNINSTALL
    
        #If the install directory exists
        if(Test-Path -Path $installDir -PathType Container)
        {
            #try and delete installDir and all sub folders and files in that folder
            try
            {
                Write-Verbose -Message "Attempting to remove all files within $installDir"
                Remove-Item -Path $installDir -Force -Recurse -ErrorAction Stop
                Write-Verbose -Message 'Successfully removed all files'
            }
            catch
            {
                Write-Warning -Message "Failed to delete program files with error: $($Error[0].Exception.Message)"
            }
        }
    
        #if the desktop shortcut exists, delete it
        if(Test-Path -Path $shortcutPath -PathType Leaf)
        {
            Remove-Item -Path $shortcutPath -Force -ErrorAction SilentlyContinue
        }
    }
    else
    {
        #THIS IS THE CODE FOR THE INSTALL
    
        #If the install directory exists, verbose tell us, otherwise create it
        if(Test-Path -Path $installDir -PathType Container)
        {
            Write-Verbose -Message "Install path $installDir already exists!"
        }
        else
        {
            try
            {
                Write-Verbose -Message "Attempting to create directory $installDir"
                #Create the Directory and discard the output
                New-Item -Path $installDir -ItemType Directory -Force -ErrorAction Stop | Out-Null
                Write-Verbose -Message 'Successfully created directory'
            }
            catch
            {
                Write-Warning -Message "Failed to create directory: $installDir, with error $($Error[0].Exception.Message)"
            }
        }
    
        #Test to see if the path exists now (as it should or something bad happenned)
        if(Test-Path -Path $installDir -PathType Container)
        {
            #Copy the files
            try
            {
                Write-Verbose "Attempting to copy icon file: $icon to $installDir"
                Copy-Item -Path $PSScriptRoot\$icon -Destination $installDir\$icon -Force -ErrorAction Stop
                Write-Verbose 'Successfully copied icon file'
                Write-Verbose "Attempting to copy appliction file: $application to $installDir"
                Copy-Item -Path $PSScriptRoot\$application -Destination $installDir\$application -Force -ErrorAction Stop
                Write-Verbose 'Successfully copied appliction file'
                $result = $true
            }
            catch
            {
                Write-Warning -Message "Failed to copy files with error $($Error[0].Exception.Message)"
            }
        }
    
        #If the files copied successfully generate the shortcut
        if($result)
        {
            #Create Windows Scripting Shell Com Object to create legacy shortcut 
            $WshShell = New-Object -ComObject WScript.Shell
        
            #Definte the properties of the shorcut
            $Shortcut = $WshShell.CreateShortcut($shortcutPath)
            $Shortcut.TargetPath = "$env:windir\System32\WindowsPowershell\v1.0\powershell.exe"
            $Shortcut.Arguments ="-WindowStyle Hidden -file `"$installDir\$application`""
            $Shortcut.IconLocation = "$installDir\$icon"
            $Shortcut.Description ="Company Name utility to connect your TIPT phone"
            $Shortcut.WorkingDirectory ="$installDir"
        
            #Create the shorcut 
            try
            {
                Write-Verbose -Message 'Attempting to Create Desktop Shortcut'
                $Shortcut.Save()
                Write-Verbose -Message 'Successfully Created Shorcut'
            }
            catch
            {
                Write-Warning -Message "Failed to create Shortcut with error: $($Error[0].Exception.Message)"
            }
        }
    }
    Write-Verbose -Message "Exiting Script"
    
    For more advanced users, I create a PowerShell module and use one of the many methods for deploying it (or use a centrally based repository that has been added to the $PSModulePath) and then let users use the function via the command line. I also have a KB article explaining how to use the module which the user can get access via the intranet using get-help module_name/function_name -online (or just use the built-in help I have provided).
     
  18. OP
    OP
    PabloEscobar

    PabloEscobar Member

    Joined:
    Jan 28, 2008
    Messages:
    14,611
    Do you setup permissions on individual things that your desktop deployed scripts might need?

    I'd like to give HR the ability to adjust Job Titles. But There are things like Dynamic Distribution Groups, that rely on certain terms being in the Job title, so I don't want to give them free reign over the Job Title field.

    Ideally, I'd like something like a webservice that fronts my scripts, takes input (probably generated from the script that will be running), runs the script as a service user, logs stuff 'somewhere' and returns something to the caller.
     
  19. Ravennoir

    Ravennoir Member

    Joined:
    May 1, 2007
    Messages:
    6,507
    Location:
    Melbourne

    For this we have the HR system do an export and there is a script that runs nightly to import the info into AD
     
  20. OP
    OP
    PabloEscobar

    PabloEscobar Member

    Joined:
    Jan 28, 2008
    Messages:
    14,611
    Does the HR system sanitize input?
    Do you check input before importing?

    We've got a Dynamic distribution group that includes anyone with "manager" in their job title.

    We get problems when lowly job titles are changed to include the word "manager"... like the head dunny cleaner becoming "sanitization manager" and then reading the managers distribution list for stuff unrelated to what they do.

    Also, I hate Dynamic distribution groups.
     

Share This Page

Advertisement: