Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
mystes
May 31, 2006

Toshimo posted:

Powershell is cool and good because I can assume that it's on every windows box at work and that I can send anyone a script and it'll work the same (pretty much) everywhere and they'll be able to edit it as needed without having Visual Studio or something on their box (also, we're trying to get the people at work limping into 1 language, I'm not going to try and teach them like 4, I want to retire some day).

Powershell is dumb and bad because its GUI support gives me Visual Aids.

If there's another language that's going to be (a) consistently available on all my windows boxes without having to install a whole 'nother software package and (b) can give me GUIs so that I can give things to non-programmers and not have them stare at me blankly, pls let me know.
Yeah this is the advantage of powershell, unfortunately. Windows comes with the c# compiler but not an editor. I've said this before, but I really wish Microsoft had worked on making c# suitable for scripting instead of making yet another language. Maybe eventually they'll at least ship the new c# interpreter with Windows.

I would still personally try to figure a way to use c# for the gui and make it configurable or even wrap it in a powershell script that could be configured rather than doing a gui in powershell, though.

mystes fucked around with this message at 20:42 on Dec 21, 2016

Adbot
ADBOT LOVES YOU

GPF
Jul 20, 2000

Kidney Buddies
Oven Wrangler

nielsm posted:

The Right thing to do would be wrapping the tasks you want to do in a Powershell module, then write a C# app calling that module through the Windows.Automation namespace.

You've got me all hot and bothered now. Could you drop an example? Here's a simple one: GUI is box with button and display area. Button fires off module that does a Get-Service on the local system. Returned list is dropped into the display box.

Daddy needs a good Xmas present.

anthonypants
May 6, 2007

by Nyc_Tattoo
Dinosaur Gum

GPF posted:

You've got me all hot and bothered now. Could you drop an example? Here's a simple one: GUI is box with button and display area. Button fires off module that does a Get-Service on the local system. Returned list is dropped into the display box.

Daddy needs a good Xmas present.
Yeah, you could do that with PowerShell.

GPF
Jul 20, 2000

Kidney Buddies
Oven Wrangler

anthonypants posted:

Yeah, you could do that with PowerShell.

...I'm going to punch you in the shirt.

Toshimo
Aug 23, 2012

He's outta line...

But he's right!
Here's a thing I did for a guy who didn't like how obfuscated the shutdown options are in Win10's start menu. Just an example of the stuff I throw together for folks here:

code:
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") 

$objForm = New-Object System.Windows.Forms.Form 
$objForm.Text = "Windows Power Options"
$objForm.Size = New-Object System.Drawing.Size(185,120) 
$objForm.StartPosition = "CenterScreen"
$objForm.FormBorderStyle = "FixedToolWindow"

$objForm.KeyPreview = $True

$objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape") 
    {$objForm.Close()}})

$ShutdownButton = New-Object System.Windows.Forms.Button
$ShutdownButton.Left = 10
$ShutdownButton.Top = 10
$ShutdownButton.Size = New-Object System.Drawing.Size(75,23)
$ShutdownButton.Text = "&Shutdown"
$ShutdownButton.Add_Click({Stop-Computer -Force})
$objForm.Controls.Add($ShutdownButton)

$RestartButton = New-Object System.Windows.Forms.Button
$RestartButton.Left = 95
$RestartButton.Top = 10
$RestartButton.Size = New-Object System.Drawing.Size(75,23)
$RestartButton.Text = "&Restart"
$RestartButton.Add_Click({Restart-Computer -Force})
$objForm.Controls.Add($RestartButton)

$HibernateButton = New-Object System.Windows.Forms.Button
$HibernateButton.Left = 10
$HibernateButton.Top = 35
$HibernateButton.Size = New-Object System.Drawing.Size(75,23)
$HibernateButton.Text = "&Hibernate"
$HibernateButton.Add_Click({
$PowerState = [System.Windows.Forms.PowerState]::Suspend;
$Force = $false;
$DisableWake = $false;
[System.Windows.Forms.Application]::SetSuspendState($PowerState, $Force, $DisableWake);})
$objForm.Controls.Add($HibernateButton)

$LogoffButton = New-Object System.Windows.Forms.Button
$LogoffButton.Left = 95
$LogoffButton.Top = 35
$LogoffButton.Size = New-Object System.Drawing.Size(75,23)
$LogoffButton.Text = "&Logoff"
$LogoffButton.Add_Click({(Get-WmiObject -Class Win32_OperatingSystem).Win32Shutdown(4)})
$objForm.Controls.Add($LogoffButton)

$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Left = 55
$CancelButton.Top = 60
$CancelButton.Text = "&Cancel"
$CancelButton.Add_Click({$objForm.Close()})
$objForm.Controls.Add($CancelButton)

$objLabel = New-Object System.Windows.Forms.Label
$objLabel.Location = New-Object System.Drawing.Size(10,20) 
$objLabel.Size = New-Object System.Drawing.Size(280,20) 
$objForm.Controls.Add($objLabel) 


$objForm.Add_Shown({$objForm.Activate()})
[void]$objForm.ShowDialog()
Now he can just pin that to his taskbar and have the functionality that he wants. There's probably a way simpler and prettier way to mock that up, but v0v.

anthonypants
May 6, 2007

by Nyc_Tattoo
Dinosaur Gum

GPF posted:

...I'm going to punch you in the shirt.
There's a lot of garbage boilerplate involved in it, as you can see from the above post. There's no New-FormObject cmdlet, it's all .Net calls.

nielsm
Jun 1, 2009



GPF posted:

You've got me all hot and bothered now. Could you drop an example? Here's a simple one: GUI is box with button and display area. Button fires off module that does a Get-Service on the local system. Returned list is dropped into the display box.

Daddy needs a good Xmas present.

Here's a stupidly simple WPF app that lists services

I don't know if the project files will work on any other machine, I picked a random System.Management.Automation.dll inside WinSxS for the reference.

GPF
Jul 20, 2000

Kidney Buddies
Oven Wrangler

nielsm posted:

Here's a stupidly simple WPF app that lists services

I don't know if the project files will work on any other machine, I picked a random System.Management.Automation.dll inside WinSxS for the reference.
That's much more straightforward than I thought it'd be. Add that dll as a reference, set a using statement for it, create a PowerShell object instance, push the commands, and invoke it. Nice.

I used to make GUIs for PS utilities I wrote at work, but that just caused more problems than solutions. Turning them into their own cmdlets worked better. One thing I'm trying to do is teach the new guys how to do their own utilities, but I'm fighting them wanting to make GUIs in PowerShell which is a huge pain in the rear end. Rather them have Visual Studio Community loaded, make them use WPF for the interface, and show them the easy way to attach powershell to it.

Thanks, nielsm. Thielsm.

nielsm
Jun 1, 2009



On the other hand, I think if you need to make pipelines, things become much more complex. Which is why you definitely want to pack all your logic into a module beforehand, so you only need a thin layer of glue in the GUI.

You can also set up "runspaces" in the programming model to do remoting directly. Unfortunately, it seems the security aspects of remoting can be difficult, at least if you want to target Exchange. I experimented with setting that up once, and never found something that worked.

Pile Of Garbage
May 28, 2007



nielsm posted:

On the other hand, I think if you need to make pipelines, things become much more complex. Which is why you definitely want to pack all your logic into a module beforehand, so you only need a thin layer of glue in the GUI.

You can also set up "runspaces" in the programming model to do remoting directly. Unfortunately, it seems the security aspects of remoting can be difficult, at least if you want to target Exchange. I experimented with setting that up once, and never found something that worked.

What security aspects of Exchange remoting did you find difficult?

nielsm
Jun 1, 2009



cheese-cube posted:

What security aspects of Exchange remoting did you find difficult?

I can make it work just fine against our on-prem Exchange through regular Powershell.

But when i tried establishing a runspace with the same parameters via the API in C#, it failed connecting in various ways. I can't remember the details, but there's no HTTPS configured or the cert is invalid, and it refuses to let me trust it regardless, giving various odd errors. Sometimes even claiming the server name not existing despite DNS working perfectly fine everywhere else.

Pile Of Garbage
May 28, 2007



Sounds like you'd possibly have to debug TLS with Wireshark which can be painful so yeah

Mo_Steel
Mar 7, 2008

Let's Clock Into The Sunset Together

Fun Shoe

GPF posted:

That's much more straightforward than I thought it'd be. Add that dll as a reference, set a using statement for it, create a PowerShell object instance, push the commands, and invoke it. Nice.

I used to make GUIs for PS utilities I wrote at work, but that just caused more problems than solutions. Turning them into their own cmdlets worked better. One thing I'm trying to do is teach the new guys how to do their own utilities, but I'm fighting them wanting to make GUIs in PowerShell which is a huge pain in the rear end. Rather them have Visual Studio Community loaded, make them use WPF for the interface, and show them the easy way to attach powershell to it.

Thanks, nielsm. Thielsm.

Show-Command works with standard cmdlets as well as custom scripts; it's not perfect by any means but you can use it to get a form like this if you do cmdlet binding parameters at the start:



Enter values for whatever parameters you want and when you hit Run it copies the resultant text back to the console so you can just hit Enter and run it, or add some piping to another cmdlet after before hitting Enter. Great learning tool.

anthonypants
May 6, 2007

by Nyc_Tattoo
Dinosaur Gum
ughhhhhhhh why can I add a collection of objects together but not subtract them

So I'd like to email users that their passwords are going to expire and I'd like to use PowerShell to generate the list of users. I've got this so far:
code:
$pdxusers = Get-ADUser -SearchBase "OU=Portland Employees,DC=domain,DC=local" -Filter * -Properties Mail,PasswordLastSet,LastLogonDate | Where-Object {$_.Enabled -eq $true}
$nycusers = Get-ADUser -SearchBase "OU=New York Employees,DC=domain,DC=local" -Filter * -Properties Mail,PasswordLastSet,LastLogonDate | Where-Object {$_.Enabled -eq $true}
$lexusers = Get-ADUser -SearchBase "OU=Lexington Employees,DC=domain,DC=local" -Filter * -Properties Mail,PasswordLastSet,LastLogonDate | Where-Object {($_.Enabled -eq $true) -and ($_.PasswordLastSet -ne $null)}

$allusers = @()
$allusers += $pdxusers += $nycusers +=$lexusers

$0days = $allusers | Select-Object Mail,PasswordLastSet,LastLogonDate | Where-Object {$_.PasswordLastSet -lt (Get-Date).AddDays(-90)} | Sort-Object PasswordLastSet
$1days = $allusers | Select-Object Mail,PasswordLastSet,LastLogonDate | Where-Object {$_.PasswordLastSet -lt (Get-Date).AddDays(-89)} | Sort-Object PasswordLastSet
$2days = $allusers | Select-Object Mail,PasswordLastSet,LastLogonDate | Where-Object {$_.PasswordLastSet -lt (Get-Date).AddDays(-88)} | Sort-Object PasswordLastSet
$3days = $allusers | Select-Object Mail,PasswordLastSet,LastLogonDate | Where-Object {$_.PasswordLastSet -lt (Get-Date).AddDays(-87)} | Sort-Object PasswordLastSet
$5days = $allusers | Select-Object Mail,PasswordLastSet,LastLogonDate | Where-Object {$_.PasswordLastSet -lt (Get-Date).AddDays(-85)} | Sort-Object PasswordLastSet
$7days = $allusers | Select-Object Mail,PasswordLastSet,LastLogonDate | Where-Object {$_.PasswordLastSet -lt (Get-Date).AddDays(-83)} | Sort-Object PasswordLastSet
$10days = $allusers | Select-Object Mail,PasswordLastSet,LastLogonDate | Where-Object {$_.PasswordLastSet -lt (Get-Date).AddDays(-80)} | Sort-Object PasswordLastSet
$15days = $allusers | Select-Object Mail,PasswordLastSet,LastLogonDate | Where-Object {$_.PasswordLastSet -lt (Get-Date).AddDays(-75)} | Sort-Object PasswordLastSet

$15days = Compare-Object -ReferenceObject $15days -DifferenceObject $10days -PassThru
$10days = Compare-Object -ReferenceObject $10days -DifferenceObject $7days -PassThru
$7days = Compare-Object -ReferenceObject $7days -DifferenceObject $5days -PassThru
$5days = Compare-Object -ReferenceObject $5days -DifferenceObject $3days -PassThru
$3days = Compare-Object -ReferenceObject $3days -DifferenceObject $2days -PassThru
$2days = Compare-Object -ReferenceObject $2days -DifferenceObject $1days -PassThru
$1days = Compare-Object -ReferenceObject $1days -DifferenceObject $0days -PassThru
I'd really like to just do $1days = $allusers -= $0days | Select-Object etc. and so on, but you can't do that. Since they're being sorted, I could also just remove the last $0days.Length from the array, but it doesn't like that either. Do I really need a loving comparative loop to iterate through each of these arrays, or is there a better way I should be doing this?

e: This is so dumb

anthonypants fucked around with this message at 02:32 on Jan 10, 2017

thebigcow
Jan 3, 2001

Bully!
PowerShell arrays have some weird limitations, can you do what you originally wanted to with a .NET ArrayList?

https://technet.microsoft.com/en-us/library/ee692802.aspx

Alternatively, is this really the best way to go about this? What do you intend to do with your 15 arrays?

anthonypants
May 6, 2007

by Nyc_Tattoo
Dinosaur Gum

thebigcow posted:

PowerShell arrays have some weird limitations, can you do what you originally wanted to with a .NET ArrayList?

https://technet.microsoft.com/en-us/library/ee692802.aspx

Alternatively, is this really the best way to go about this? What do you intend to do with your 15 arrays?
The RemoveRange() method is basically what I was aiming for above, but even that won't work if, say, $1days has the same count as $0days. So I'm going to build a function to compare them instead. gently caress to PowerShell

anthonypants
May 6, 2007

by Nyc_Tattoo
Dinosaur Gum
Okay so apparently there's a Compare-Object cmdlet that can literally subtract arrays, but only if the arrays are sorted. What the gently caress

nielsm
Jun 1, 2009



Likely since that allows them to guarantee the algorithmic complexity. When both inputs are sorted on the same criteria, the algorithm needs to do at most M+N comparisons, and the inputs can even be forward-only iterators or generators instead of being random access lists. So from a CS standpoint, it makes good sense.

The Fool
Oct 16, 2003


I have a powershell script that has been giving me a headache today.

The script queries a subsidiaries ad for user information, then updates the users account in our ad. If the account doesn't exist, it creates it.

This script works flawlessly if the account already exists, however, if the script has to create a new account, it does so, but all of the subsequent "Set-ADUser" commands fail. If I run the script a second time, it updates everything. Hell, if I even tell the function to run twice in a row, it spits out a bunch of errors on the first pass, then works fine on the second pass.

I have no idea what the gently caress to do at this point.

Toshimo
Aug 23, 2012

He's outta line...

But he's right!

The Fool posted:

I have a powershell script that has been giving me a headache today.

The script queries a subsidiaries ad for user information, then updates the users account in our ad. If the account doesn't exist, it creates it.

This script works flawlessly if the account already exists, however, if the script has to create a new account, it does so, but all of the subsequent "Set-ADUser" commands fail. If I run the script a second time, it updates everything. Hell, if I even tell the function to run twice in a row, it spits out a bunch of errors on the first pass, then works fine on the second pass.

I have no idea what the gently caress to do at this point.

Paste ur script.

Walked
Apr 14, 2003

Post some source?

E:b

The Fool
Oct 16, 2003


oh god sanitizing variable names

This function is called from Main. If I call it twice, I don't get errors.

code:
function Get-UserInfo($ID)
{
  Try
  {
    $ADUser = Get-ADUser -Identity $ID -Credential $cred -Server $dc -Properties $userPropertyList
  }
  Catch
  {
    $errorText = "User " + $ID + " doesn't exist in CAC AD. Creating user now."
    Write-Error $errorText
    Create-NewUser $ID
    $ADUser = Get-ADUser -Identity $ID -Credential $cred -Server $dc -Properties $userPropertyList
  }
  return $ADUser
}
This function creates the new user.

code:
function Create-NewUser($ID)
{
  $UPN = $ID + "@contoso.com"
  New-ADUser -Name $ID -AccountPassword $defaultPassword -UserPrincipalName $UPN -ChangePasswordAtLogon $true -Credential $cred -Enabled $true
}
The Main function
code:
function Main([string]$UserID)
{
    $SubUserInfo = Get-SubUserInfo $UserID | Select-Object $userPropertyList
    $MyUserInfo = Get-UserInfo $UserID | Select-Object $userPropertyList
    $MyUserInfo = Get-UserInfo $UserID | Select-Object $userPropertyList # If I run this twice on a new user, the Set-ADUser commands work the second time.

    if (!$SubUserInfo.Enabled -or !$MyUserInfo.Enabled) {
     Write-Error "User account is disabled."
     Exit 1
    }

    Set-MyADUserProperties $SubUserInfo $MyUserInfo
    $updatedUser = Get-UserInfo $UserID | Select-Object $userPropertyList
    Write-Output $updatedUser
}

Walked
Apr 14, 2003

The Fool posted:

oh god sanitizing variable names

This function is called from Main. If I call it twice, I don't get errors.

code:
function Get-UserInfo($ID)
{
  Try
  {
    $ADUser = Get-ADUser -Identity $ID -Credential $cred -Server $dc -Properties $userPropertyList
  }
  Catch
  {
    $errorText = "User " + $ID + " doesn't exist in CAC AD. Creating user now."
    Write-Error $errorText
    Create-NewUser $ID
    $ADUser = Get-ADUser -Identity $ID -Credential $cred -Server $dc -Properties $userPropertyList
  }
  return $ADUser
}
This function creates the new user.

code:
function Create-NewUser($ID)
{
  $UPN = $ID + "@contoso.com"
  New-ADUser -Name $ID -AccountPassword $defaultPassword -UserPrincipalName $UPN -ChangePasswordAtLogon $true -Credential $cred -Enabled $true
}
The Main function
code:
function Main([string]$UserID)
{
    $SubUserInfo = Get-SubUserInfo $UserID | Select-Object $userPropertyList
    $MyUserInfo = Get-UserInfo $UserID | Select-Object $userPropertyList
    $MyUserInfo = Get-UserInfo $UserID | Select-Object $userPropertyList # If I run this twice on a new user, the Set-ADUser commands work the second time.

    if (!$SubUserInfo.Enabled -or !$MyUserInfo.Enabled) {
     Write-Error "User account is disabled."
     Exit 1
    }

    Set-MyADUserProperties $SubUserInfo $MyUserInfo
    $updatedUser = Get-UserInfo $UserID | Select-Object $userPropertyList
    Write-Output $updatedUser
}

Gut shot from my phone, what happens if you sleep for 10 sec before calling the problematic function?

The Fool
Oct 16, 2003


Walked posted:

Gut shot from my phone, what happens if you sleep for 10 sec before calling the problematic function?

Tried Sleeps up to 30 seconds and they didn't help.

anthonypants
May 6, 2007

by Nyc_Tattoo
Dinosaur Gum

The Fool posted:

oh god sanitizing variable names

This function is called from Main. If I call it twice, I don't get errors.

code:
function Get-UserInfo($ID)
{
  Try
  {
    $ADUser = Get-ADUser -Identity $ID -Credential $cred -Server $dc -Properties $userPropertyList
  }
  Catch
  {
    $errorText = "User " + $ID + " doesn't exist in CAC AD. Creating user now."
    Write-Error $errorText
    Create-NewUser $ID
    $ADUser = Get-ADUser -Identity $ID -Credential $cred -Server $dc -Properties $userPropertyList
  }
  return $ADUser
}
This function creates the new user.

code:
function Create-NewUser($ID)
{
  $UPN = $ID + "@contoso.com"
  New-ADUser -Name $ID -AccountPassword $defaultPassword -UserPrincipalName $UPN -ChangePasswordAtLogon $true -Credential $cred -Enabled $true
}
The Main function
code:
function Main([string]$UserID)
{
    $SubUserInfo = Get-SubUserInfo $UserID | Select-Object $userPropertyList
    $MyUserInfo = Get-UserInfo $UserID | Select-Object $userPropertyList
    $MyUserInfo = Get-UserInfo $UserID | Select-Object $userPropertyList # If I run this twice on a new user, the Set-ADUser commands work the second time.

    if (!$SubUserInfo.Enabled -or !$MyUserInfo.Enabled) {
     Write-Error "User account is disabled."
     Exit 1
    }

    Set-MyADUserProperties $SubUserInfo $MyUserInfo
    $updatedUser = Get-UserInfo $UserID | Select-Object $userPropertyList
    Write-Output $updatedUser
}
What's in $MyUserInfo when it's run the first time? Can you set a breakpoint on it? Also I don't see any Set-ADUser cmdlets which is what your first post said didn't work? I see a Set-MyADUserProperties in there but you didn't post that function.

The Fool
Oct 16, 2003


So, when I was sanitizing the variable names I noticed a Write-Output that should have been a Write-Error. I fixed that in the source script, and now it's working correctly.

Thanks virtual rubber ducks.

Toshimo
Aug 23, 2012

He's outta line...

But he's right!

The Fool posted:

So, when I was sanitizing the variable names I noticed a Write-Output that should have been a Write-Error. I fixed that in the source script, and now it's working correctly.

Thanks virtual rubber ducks.

Zaepho
Oct 31, 2013

The Fool posted:

I have a powershell script that has been giving me a headache today.

The script queries a subsidiaries ad for user information, then updates the users account in our ad. If the account doesn't exist, it creates it.

This script works flawlessly if the account already exists, however, if the script has to create a new account, it does so, but all of the subsequent "Set-ADUser" commands fail. If I run the script a second time, it updates everything. Hell, if I even tell the function to run twice in a row, it spits out a bunch of errors on the first pass, then works fine on the second pass.

I have no idea what the gently caress to do at this point.

I usually see this when the calls go out to different DCs. Have your script find a domain controller to use and pass that DC to every one of the AD commands.

FISHMANPET
Mar 3, 2007

Sweet 'N Sour
Can't
Melt
Steel Beams
OK I'm tearing my hair out over here and I just have no idea how I'm supposed to move forward.

We have a powershell script. We run it to build new machines. We have an Enterprise Github subscription so the script is "stored" there. Our team (7 of us) share a single RDS server that we use as a tools server it's where all our "stuff" is. I want to keep our script in a place on that server, such that it will always be the latest version. Github is the "source of truth" so to speak and there should always be a copy of that source of truth on our tools server.

I've come up with a number of possibilities on how to solve this problem, and they all seem bad, so I'm worried that something we're doing is wrong and should be done differently.
The dumbest brute force method is to have a scheduled task that runs every <unit of time> to execute a script that does a git pull. That's totally non-elegant, and there's the (minor) issue of what happens when the script is updated in Github but the scheduled task hasn't been run yet.
I could setup a github post-commit webhook. I could then either send that webhook to an azure automation service that would then fire off a git pull on the tools server. Or I could custom write something in powershell that will listen for that webhook and do a git pull when it receives the notification. Both of those seem convoluted and require a lot of custom programming.
I could go all out and setup a CI process. I've gone slightly down the rabbit hole of looking at Visual Studio Team Services, but this is dramatically overkill, and is in no way aimed at a sys admin, but at a programmer. I could make it work, but there don't appear to be any built in "build" actions that say "copy this git repo when it changes" so I'm left writing my own script to do the git pull and having VSTS execute that when the repo changes.

None of this stuff is particularly complicated (maybe writing a powershell service to listen for a web request is...) but it's still special snowflake code that I have to write myself rather than just copy from someone else smarter than me on the internet. Which is kind of the root of my problem, this doesn't seem like an uncommon scenario yet I can't find any information about how to easily solve this problem so I'm left wondering if I'm solving the wrong problem, in which case what should I be doing differently?

Walked
Apr 14, 2003

FISHMANPET posted:

OK I'm tearing my hair out over here and I just have no idea how I'm supposed to move forward.

We have a powershell script. We run it to build new machines. We have an Enterprise Github subscription so the script is "stored" there. Our team (7 of us) share a single RDS server that we use as a tools server it's where all our "stuff" is. I want to keep our script in a place on that server, such that it will always be the latest version. Github is the "source of truth" so to speak and there should always be a copy of that source of truth on our tools server.

I've come up with a number of possibilities on how to solve this problem, and they all seem bad, so I'm worried that something we're doing is wrong and should be done differently.
The dumbest brute force method is to have a scheduled task that runs every <unit of time> to execute a script that does a git pull. That's totally non-elegant, and there's the (minor) issue of what happens when the script is updated in Github but the scheduled task hasn't been run yet.
I could setup a github post-commit webhook. I could then either send that webhook to an azure automation service that would then fire off a git pull on the tools server. Or I could custom write something in powershell that will listen for that webhook and do a git pull when it receives the notification. Both of those seem convoluted and require a lot of custom programming.
I could go all out and setup a CI process. I've gone slightly down the rabbit hole of looking at Visual Studio Team Services, but this is dramatically overkill, and is in no way aimed at a sys admin, but at a programmer. I could make it work, but there don't appear to be any built in "build" actions that say "copy this git repo when it changes" so I'm left writing my own script to do the git pull and having VSTS execute that when the repo changes.

None of this stuff is particularly complicated (maybe writing a powershell service to listen for a web request is...) but it's still special snowflake code that I have to write myself rather than just copy from someone else smarter than me on the internet. Which is kind of the root of my problem, this doesn't seem like an uncommon scenario yet I can't find any information about how to easily solve this problem so I'm left wondering if I'm solving the wrong problem, in which case what should I be doing differently?

I've been through this whole thought process over and over again myself.

I'm using Jenkins configured to poll SCM for changes, and to publish artifacts to a CIFS share on 'build' completion.
It helps that I've also set this up to compile all our DSC mof files and the DSC server is configured to consume those from the artifacts share.

This is a terrible blog post I wrote that covers the DSC side of what I'm doing: https://i-py.com/2017/jenkins-dsc-ci/ - but its the same basic design for all our PowerShell stuff.

Walked fucked around with this message at 01:56 on Jan 20, 2017

Mo_Steel
Mar 7, 2008

Let's Clock Into The Sunset Together

Fun Shoe

FISHMANPET posted:

OK I'm tearing my hair out over here and I just have no idea how I'm supposed to move forward.

We have a powershell script. We run it to build new machines. We have an Enterprise Github subscription so the script is "stored" there. Our team (7 of us) share a single RDS server that we use as a tools server it's where all our "stuff" is. I want to keep our script in a place on that server, such that it will always be the latest version. Github is the "source of truth" so to speak and there should always be a copy of that source of truth on our tools server.

I've come up with a number of possibilities on how to solve this problem, and they all seem bad, so I'm worried that something we're doing is wrong and should be done differently.
The dumbest brute force method is to have a scheduled task that runs every <unit of time> to execute a script that does a git pull. That's totally non-elegant, and there's the (minor) issue of what happens when the script is updated in Github but the scheduled task hasn't been run yet.
I could setup a github post-commit webhook. I could then either send that webhook to an azure automation service that would then fire off a git pull on the tools server. Or I could custom write something in powershell that will listen for that webhook and do a git pull when it receives the notification. Both of those seem convoluted and require a lot of custom programming.
I could go all out and setup a CI process. I've gone slightly down the rabbit hole of looking at Visual Studio Team Services, but this is dramatically overkill, and is in no way aimed at a sys admin, but at a programmer. I could make it work, but there don't appear to be any built in "build" actions that say "copy this git repo when it changes" so I'm left writing my own script to do the git pull and having VSTS execute that when the repo changes.

None of this stuff is particularly complicated (maybe writing a powershell service to listen for a web request is...) but it's still special snowflake code that I have to write myself rather than just copy from someone else smarter than me on the internet. Which is kind of the root of my problem, this doesn't seem like an uncommon scenario yet I can't find any information about how to easily solve this problem so I'm left wondering if I'm solving the wrong problem, in which case what should I be doing differently?

What about a separate "launcher" script? Something like this:

Create-NewMachine.ps1 calls a function inside itself that retrieves the most recent copy of the actual working script (we'll say "Create-NewMachineWorker.ps1"); once the most recent copy is pulled down to the local machine, Create-NewMachine.ps1 then calls Create-NewMachineWorker.ps1 and that script does all the things you want the script to actually do.

It's a little clunky but should be functional; the launcher script shouldn't really ever need to change, and as long as it always retrieves the current copy from GitHub at the very start before calling it then you're guaranteed to have the most recent copy whenever you're running it to setup a new machine.

GPF
Jul 20, 2000

Kidney Buddies
Oven Wrangler

Mo_Steel posted:

What about a separate "launcher" script? Something like this:
<snip>

Just wondering...is there some kind of function that's part of GitHub where you can pull down a hash of what's on there rather than the whole script? If there was something like that, it'd be easy enough to grab the Github hash, then hash your local copy and do a comparison using that launcher script idea. Hash doesn't match, pull the remote "more truthy" script. Hash matches, run the local copy.

Walked
Apr 14, 2003

GPF posted:

Just wondering...is there some kind of function that's part of GitHub where you can pull down a hash of what's on there rather than the whole script? If there was something like that, it'd be easy enough to grab the Github hash, then hash your local copy and do a comparison using that launcher script idea. Hash doesn't match, pull the remote "more truthy" script. Hash matches, run the local copy.

Looks like the git api just dumps the whole file back anyways, but here you go

code:
$a = iwr "https://api.github.com/repos/walked/cDscDocker/contents/cDscDocker.psm1"
($a.Content | ConvertFrom-Json).sha
(but the http response to the webrequest contains the whole file in base64 encoding anyways so :toot: )

CLAM DOWN
Feb 13, 2007




I have a single command within a script that takes forever to process (no way around this) and I wish MS would add a way for me to display a progress bar for this single command :( Write-Progress is annoying and limited.

Walked
Apr 14, 2003

CLAM DOWN posted:

I have a single command within a script that takes forever to process (no way around this) and I wish MS would add a way for me to display a progress bar for this single command :( Write-Progress is annoying and limited.

Just do it the microsoft way; have it load at a linear rate until it's at ~90% and then just let it sit there without explanation until the task completes or fails.

:negative:

Mo_Steel
Mar 7, 2008

Let's Clock Into The Sunset Together

Fun Shoe

CLAM DOWN posted:

I have a single command within a script that takes forever to process (no way around this) and I wish MS would add a way for me to display a progress bar for this single command :( Write-Progress is annoying and limited.

Is the single command a consistent amount of time? It's ugly but you could use Measure-Command in advance so you know the expected time and then have PS run the command as a background job while showing a progress bar with the time remaining, then when the timer is up change it to a new progress loop that says "finishing" and then loops to check and see if the background job completed before continuing. Pretty janky but if you aren't able to run the command in a loop there's not a good way of estimating how long the operation of a command might take afaik.

Would be really cool to have as a flag though in a form like -EstimateProgress so you could run "gci -recurse -estimateprogress" , I just have no idea if that were possible what sort of overhead it would tack on.

Bunni-kat
May 25, 2010

Service Desk B-b-bunny...
How can-ca-caaaaan I
help-p-p-p you?
Hi! I posted this in the ticketing thread in the main section, but then I thought there must be a powershell thread, so:

I just started a new job, and I've never used powershell before. I got a request to modify 15 users in AD, changing userAccountControl attribute. How can I powershell this?

Also, I looked at the op but the references are all 7 years old. What's the new hot book to read to learn?

Thanks guys!

anthonypants
May 6, 2007

by Nyc_Tattoo
Dinosaur Gum

Avenging_Mikon posted:

Hi! I posted this in the ticketing thread in the main section, but then I thought there must be a powershell thread, so:

I just started a new job, and I've never used powershell before. I got a request to modify 15 users in AD, changing userAccountControl attribute. How can I powershell this?

Also, I looked at the op but the references are all 7 years old. What's the new hot book to read to learn?

Thanks guys!
People seem to like PowerShell in a Month of Lunches, and the third edition is from last month.

Assuming you have a list of users in an OU,
code:
$users = Get-ADUser -SearchBase "OU=Organizational Unit,DC=domain,DC=local" -Filter *
foreach ($u in $users) {
	Set-ADUser $u -AccountNotDelegated $true
	#use Set-ADAccountControl if the parameter you're looking for is missing from Set-ADUser
	Set-ADAccountControl $u -MNSLogonAccount $false
}

CLAM DOWN
Feb 13, 2007




Mo_Steel posted:

Is the single command a consistent amount of time?

Nope it's variable, and yeah can't run it in a loop :( I know this isn't possible I'm just venting.

Walked posted:

Just do it the microsoft way; have it load at a linear rate until it's at ~90% and then just let it sit there without explanation until the task completes or fails.

:negative:

I'm the one running this script so I would only be lying to myself and I don't got no time for that poo poo

Adbot
ADBOT LOVES YOU

Bunni-kat
May 25, 2010

Service Desk B-b-bunny...
How can-ca-caaaaan I
help-p-p-p you?

anthonypants posted:

People seem to like PowerShell in a Month of Lunches, and the third edition is from last month.

Just ordered it. I probably won't get to powershell much, but this is the first excuse I've had to use it at all!

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply